nrinaudo / fetch [DEPRECATED]

Scala HTTP client library

GitHub

fetch

Build Status Coverage Status

Fetch is a Scala wrapper for Java HTTP client implementations. It comes with a default java.net.URLConnection connector, with more planned in the future.

It's meant to be simple, fluent and functional. Suggestions and constructive criticisms are more than welcome.

Getting Fetch

The current version is 0.2.1, which can be added to your project with the following line in your SBT build file:

libraryDependencies += "com.nrinaudo" %% "fetch-core" % "0.2.1"

Querying

The first step to performing a request is building the URL to connect to. This is typically done through the Url companion object:

// String-based creation, returns None if the specified String is not a valid URL.
Url.parse("https://graph.facebook.com/me") // Option[Url]

// URI-based creation, can also fail (typically if the URI is relative).
Url.fromUri(new java.net.URI("https://graph.facebook.com/me")) // Option[Url]

// Step-by-step construction
(Protocol.Https :/ "graph.facebook.com") / "me"

Once an instance of Url is available, it can be turned into a Request, provided an implicit engine is in scope:

implicit val engine = net.UrlEngine(5000, 5000)

val req = Request((Protocol.Https :/ "graph.facebook.com") / "me")

Common HTTP headers can be manipulated through helper methods in Request:

def createRequest = ???

val req = createRequest.acceptGzip               // Will receive GZIPed content if the remote server supports it
                       .accept(MimeType.Json)    // Request JSON responses
                       .auth("user", "password") // "Basic-authentifies" as user
                       .userAgent("CustomAgent") // Sets the request's user agent.
                       .GET                      // Performs a GET request.

Applying a request will execute it and return an instance of Response[ResponseEntity]. Since Request is a functor, however, it's usually more convenient to map to a better response type:

def createRequest = ???

// req is an instance of Request[String].
val req = createRequest.map {
  case res @ Status.Success(_) => res.body.as[String]
  case res @ Status(s)         =>
    res.empty()
    throw new Exception("Error " + s.code)
}

We were requesting JSON content, however, so an instance of String is not terribly useful. Fortunately, implicit instances of EntityParser can be used to transform a ResponseEntity into a more immediately useful type.

Using the json4s-jackson Fetch module, for example, one would write:

import com.nrinaudo.fetch.json4s._

def createRequest = ???

// req is an instance of Request[JValue].
val req = createRequest.map {
  case res @ Status.Success(_) => res.body.as[JValue]
  case res @ Status(s)         =>
      res.empty()
      throw new Exception("Error " + s.code)
}

Submitting content

Content submission is done by calling a request's apply(RequestEntity) method and setting the appropriate HTTP method.

For example:

def createRequest = ???

createRequest.PUT.apply(RequestEntity("Some text content"))

// There's an implicit conversion from string to request entity, so the previous line can also be written as:
createRequest.PUT.apply("Some text content")

// Or, even if it's a bit misleading:
createRequest.PUT("Some text content")

It's of course possible to write custom type converters. The following (fairly useless) code will allow you to submit instances of Int:

implicit def intToEntity(value: Int) = RequestEntity.chars { _.write(value.toString) }

An example of such a mechanism is the json4s-jackson Fetch module, which declares implicit conversion from a JValue to a RequestEntity.