http-verbs-java

http-verbs is a Java library bridging to http-verbs.

Adding to your build

In your SBT build add:

resolvers += Resolver.bintrayRepo("hmrc", "releases")

libraryDependencies += "uk.gov.hmrc" %% "http-verbs-java" % "x.x.x"

Adding to your app

Each verb is available as both an agnostic Http___ interface and a play-specific WS___ interface. They can be used as default interfaces:

import uk.gov.hmrc.play.java.http.*;
import uk.gov.hmrc.play.java.http.ws.*;

class ConnectorWithMixins implements HttpGet, HttpPost {
    ...
}

Making HTTP Calls

Each verb supplies a single matching method, which takes a URL, and a request body if appropriate:

http.doGet("http://gov.uk/hmrc", headerCarrier)
http.doDelete("http://gov.uk/hmrc", headerCarrier)
http.doPost("http://gov.uk/hmrc", body = "hi there")
http.doPut("http://gov.uk/hmrc", body = "hi there")

All calls require a HeaderCarrier.

Headers from the carrier are added to every request. This allows:

  • Common headers to be configured for all requests
  • Headers from an inbound call to be propagated to an outbound one (we do this by implicitly converting Play's Request into a HeaderCarrier)

Response Handling

All verbs return Futures. By default, a HttpResponse is returned for successful responses, which gives access to the status code, raw body and headers:

val r1 = http.GET("http://gov.uk/hmrc") // Returns an HttpResponse
val r2 = http.GET[HttpResponse]("http://gov.uk/hmrc") // Can specify this explicitly
r1.map { r =>
  r.status
  r.body
  r.allHeaders
}

Errors

To make microservice development simple, responses with non-200 status codes will cause a failed Future to be returned with a typed exception. This allows failures to be propagated back naturally.

Status Code Exception
400 BadRequestException
404 NotFoundException
4xx Upstream4xxResponse
5xx Upstream5xxResponse

For all possible exception types, see the hmrc/http-exceptions project

If some failure status codes are expected in normal flow, recover can be used:

httpGet.GET("url") recover {
  case nf: NotFoundException => ...
  case se: Upstream5xxResponse => ...
}

or if you expect responses which indicate no content, you can use an Option[...] return type.

Response Types

http-verbs can automatically map responses into richer types.

JSON responses

If you have an implicit play.api.libs.json.Reads[A] for your type in scope, just specify that type and it will be automatically deserialised.

import play.api.libs.json._
case class MyCaseClass(a: String, b: Int)
implicit val f = Json.reads[MyCaseClass]
http.GET[MyCaseClass]("http://gov.uk/hmrc") // Returns an MyCaseClass de-serialised from JSON
HTML responses

If you wish to use HTML responses, Play's Html type can be used:

import play.twirl.api.Html
http.GET[Html]("http://gov.uk/hmrc") // Returns a Play Html type

Potentially empty responses

If you expect to receive a 204 or 404 response in some circumstances, then you can add Option[...] to your return type:

http.GET[Option[MyCaseClass]]("http://gov.uk/hmrc") // Returns None, or Some[MyCaseClass] de-serialised from JSON
http.GET[Option[Html]]("http://gov.uk/hmrc") // Returns a None, or a Play Html type

Extension & Customisation

Response handling is implemented via the HttpReads[A] typeclass, which is responsible for converting the raw response into either an exception or the specified type. Default implementations of HttpReads[A] have been provided in its companion object to cover common use cases, but clients may provide their own implementations if required.

Hooks

You can now set up http-verbs to run a series of callbacks when the future representing an http request completes - these are known as hooks. Hooks are used by play-auditing in order to wire up implicit auditing.

A hook looks like this:

object MyHook extends HttpHook {
  override def apply(url: String, verb: String, body: Option[_], responseF: Future[HttpResponse])(implicit hc: HeaderCarrier): Unit = {
    responseF.map {
      response => // do something on success
    }.recover {
      case e: Throwable => // do something on exception
    }
  }
}

And is registered with http-verbs like this:

object WSHttp extends WSGet with WSPut with WSPost with WSDelete with WSPatch {
  override val hooks = Seq(MyHook, AnotherHook)
  ...
  ...
}

License

This code is open source software licensed under the Apache 2.0 License.