Tuesday, December 18, 2012

A Simple Java Http Client

I recently needed to make an HTTP call from my AppEngine application, which uses the standard java.net classes for its urlFetch service.  Doing something as simple as an HTTP request in Java is a lot more complicated than one would hope.  Since I didn't find the process intuitive at all, I wrote this little Java HTTP client that works the way I think of HTTP.

Along the way I got to experiment with generics, which allowed me to make chained method calls so I can effectively make the whole HTTP request and get the response in one line of code (sort of).  The whole client consists of three classes and uses only core java classes, so no external libraries are needed (and it can run on AppEngine).

Message.java

This class forms the basis for the Request and Response classes.  Message is an abstract class, and contains only those things that are common to both Requests and Responses, e.g. headers and a body.

Request.java

This class does most of the heavy lifting.  It contains fields and methods for dealing with the URL and Query String, as well as several private methods that handle the messy "under the covers" networking stuff.

Response.java

This class has a few things that are only relevant to a Response, e.g. the response code and message.

How to use it:


Here's an example of a simple GET request:

// Issues a GET to Google
Response httpResponse = new Request("http://example.com")
        .getResource();

String responseBody = httpResponse.getBody();

Here's a GET request with a header and a query parameter specified:

Response httpResponse = new Request("http://example.com")
        .addHeader("x-my-header", "foobar")
        .addQueryParameter("foo", "bar")
        .getResource();

String responseBody = httpResponse.getBody();

Here's a more complicated example of a POST request with query parameters and custom headers:

// Posts a simple JSON object to the server
Response httpResponse = new Request("http://example.com")
        .addHeader("x-my-header", "foobar")
        .addQueryParameter("foo", "bar")
        .setBody("{foo: 'bar'}")
        .postResource();

String responseBody = httpResponse.getBody();


I put the whole thing on GitHub if anyone wants to try it out.  Plus, a Tip of the Hat goes to Ben Fagin for a great blog post explaining how to use generics and inheritance to create fluent APIs.

5 comments:

  1. Great work! This is a real simple API and I was up and running within seconds. Other HTTP clients seem to have lost their way. 10/10 for simplicity.

    ReplyDelete
  2. Thanks for sharing. I did something similar for work too, but not as nicely compacted as your design, but equally simple to use. Will see if I can port that out to an OSS version some day.

    ReplyDelete
  3. Thanks for sharing. I did something similar at work, though not as nicely compact as yours in chaining calls, but equally simple to use. Hope to get to port out an OSS version of mine some day.

    ReplyDelete
  4. Awesome. Best HTTP client I've found for simple stuff. I love that it has no dependencies. The only other feature I would consider adding is basic-auth.

    ReplyDelete
  5. Nice work! Have you though about adding a addFormData() method, similar to addQueryParameter()?

    ReplyDelete