In the world of Java, there are plenty of HTTP clients from which to choose. Nevertheless, a year ago, I decided to create a new one because none of the other clients satisfied fully all of my requirements. I wanted mine to have a fluent interface, be immutable and extendable.
String html = new JdkRequest("https://www.google.com") .uri().path("/users").queryParam("id", 333).back() .method(Request.GET) .header("Accept", "text/html") .fetch() .as(RestResponse.class) .assertStatus(HttpURLConnection.HTTP_OK) .body();
Besides immutability, a fluent interface and extendability, one of my primary requirements was simplicity. The client must be simple and easy to use. In most cases, I need only to make an HTTP request and parse the JSON response to return a value. For example, this is how I use the new client to return a current EUR rate:
String rate = new JdkRequest("http://www.getexchangerates.com/api/latest.json") .header("Accept", "application/json") .fetch() .as(JsonResponse.class) .json().readArray().getJsonObject(0) .getString("EUR");
I assume that the above is easy to understand and maintain.
jcabi-http has a 100% fluent interface, which means that the entire server interaction fits into one Java statement. Why is this important? I think that a fluent interface is the most compact and expressive way to perform multiple imperative calls. To my knowledge, none of the existing libraries enable this type of fluency.
The request object itself is immutable, unlike requests in all other HTTP libraries I've seen. This means that every time you make a change to the object it returns a new instance:
Request first = new JdkRequest("http://google.com"); Request second = first.header("Accept", "text/xml");
In this example, the first object stays the same after we add a new header to it. The second object returned behaves exactly as the first one, but with an extra HTTP header. This may become very important when you start passing your HTTP request as an argument to a method or as an encapsulated stated into another object.