Monday, January 3, 2011

Day 7: Asynchronous Http Client

Since I'm trying to get into the habit of doing *everything* in Scala, and I needed to write a Confluence client, I wanted to see how hard it would be to do that in Scala as well. That quickly detoriated into an attempt to write a convenience layer around async-http-client. I'm still not sure if this is going anywhere, but I will show you what I have anyway.

Async Http Client


... is an awesome asynchronous HTTP client. Wherever I looked, I couldn't find a Scala version of it. There is a Clojure version of it though. I didn't take much time to get any inspiration from that though.

How to use it?


This is what the wrapper library allows you to do. First of all, it allows you to "GET" a resource and return only part of it.

val http = new Http
val statusCode = 
  http.get("http://www.xebia.com/")
      .returning(Http.statusCode)
statusCode.get should equal (200)

Now, in reality, you obviously want something else. You want to get a couple of values, for instance. That also works. So, instead of the returning the full underlying response class, it just returns the values you're interested in, as a tuple.

val http = new Http
val result = 
  http.get("http://www.xebia.com/")
      .returning(Http.statusCode, Http.contentType)
val (statusCode, contentType) = result.get
statusCode should equal (200)
contentType should startWith ("text/html")

And last but not least, if that's not what you are after, then you can still get the full response object.

val http = new Http
val result = 
  http.get("http://www.xebia.com/")
      .returning(Http.fullResponse)
result.get.getContentType 
  should startWith ("text/html")

Currently, the returning method takes functions like these:

(Response) => T

... and if you pass in a couple, you get response tuples existing of values matching the return types of those functions.

How useful is this?


Honestly? Probably not all that much. I need to look at it again in some time to see if there is any point in doing it like this.

3 comments:

  1. Not much sense in using an async http client library if you are going to wait until it finishes in the next line, is there ? :)

    I would like to pass in a callback function that will get called when the GET is actually finished. Like so:

    http.get("http://www.xebia.com/") { (response: Response) =>
    ...process the response
    }

    Now that would be cool :)

    ReplyDelete
  2. Hehehe. That would actually be easy. But you're right. I've just looked at the first few examples on how it's commonly used, also in Clojure, and that's it.

    However, if you imagine a uris: List, then you can picture mapping this to a collection of futures. So you would get some advantage over doing it the linear way. However if you - afterwards - would go over the futures in sequence, there might still be a chance that you would be waiting for the one that times out.

    ReplyDelete
  3. In fact, you can already do it now. Simply pass in a function that returns a Unit. It might be a future that you're getting back, but that doesn't mean you need to wait for it to complete.

    ReplyDelete