1. Introduction

The Grails HTTP project provides a set of core utility classes for dealing with the HTTP protocol.

From a user perspective, the current most useful of these is an Asynchronous HTTP client built on Netty that integrates seamlessly with Grails framework.

Note that this client does not require Grails itself, and can easily be used standalone or as an independent HTTP client.

2. HTTP Client

2.1. Introduction

The HTTP client is built on the Netty toolkit and is designed as a non-blocking replacement for the REST Client Builder plugin for Grails.

To get started with the HTTP client you should declare a dependency on the grails-http-client project in your build.gradle file:

compile "org.grails:http-client:VERSION"

The entry point for the API is the AsyncRestBuilder class.

Typically there should be a single instance of this class ( a Spring bean for example) that you reuse to avoid the cost of repeatedly creating the thread pools that Netty requires to operate.

If you are using Grails then there is a Grails plugin called async-http-builder you can use to get started:

compile "org.grails.plugins:async-http-builder:VERSION"

The most simple use case for obtaining content can be seen below:

import grails.http.client.*
import grails.async.*
...
AsyncHttpBuilder client = new AsyncHttpBuilder()
Promise<HttpClientResponse> p = client.post("https://localhost:8080/foo/bar") {
    contentType 'application/json'
    json {
        title "Ping"
    }
}
p.onComplete { HttpClientResponse resp ->
    assert resp.json.title == 'Pong'
}

The AsyncHttpBuilder has methods for each HTTP method type (GET, POST, PUT etc.), each one returning a Promise.

You can attach completion or error listeners to the Promise instance. For more information on promises see the guide in the Grails documentation.

2.2. Sending & Receiving JSON

To send JSON you can use the json method which uses an instance of Groovy’s StreamingJsonBuilder:

Promise<HttpClientResponse> p = client.post("https://localhost:8080/foo/bar") {
    contentType 'application/json'
    json {
        title "Hello World"
    }
}

The json method is defined within the HttpMessageBuilder which allows you to build JSON with StreamingJsonBuilder in a variety of ways:

json [1,2,3] // a JSON array
json title:"Hello World" // a map

To read a JSON response use the json property of the HttpClientResponse:

p.onComplete { HttpClientResponse resp ->
    assert resp.json.title == 'Pong'
}

2.3. Sending & Receiving XML

To send XML you can use the xml method which uses an instance of Groovy’s StreamingMarkupBuilder:

Promise<HttpClientResponse> p = client.post("https://localhost:8080/foo/bar") {
    xml {
        message {
            title "Ping"
        }
    }
}

The xml method is defined within the HttpMessageBuilder class.

To read an XML response use the xml property of the HttpClientResponse, which returns a Groovy GPathResult:

p.onComplete { HttpClientResponse resp ->
    assert resp.xml.message.text() == 'Pong'
}

2.4. Forms and Multipart Requests

To send a request of type application/x-www-form-urlencoded use the form method defined by HttpRequestBuilder:

Promise<HttpClientResponse> p = client.post("http://localhost:8080/foo/bar") {
    form {
        foo = "bar"
    }
}

To upload files using a multipart request use the multipart method:

client.post("http://localhost:8080/foo/bar") {
    multipart {
        foo = "bar"
        myFile = new File(..)
    }
}

You can either assign a File, an InputStream or a byte[] for files to be uploaded. Alternatively you can use the file method of HttpRequestBuilder to further customize the file upload.

2.5. Testing

To facilitate testing and mocking you can use the TestAsyncHttpBuilder class.

The TestAsyncHttpBuilder provides the ability to mock HTTP responses and avoid external HTTP requests within your unit tests.

For example:

TestAsyncHttpBuilder client = new TestAsyncHttpBuilder()
client.expect {
    uri '/foo/bar'
    method "GET"
    accept 'application/json'
}.respond {
    ok()
    json {
        title "Hello"
    }
}
...
Promise<HttpClientResponse> p = client.get("https://localhost:8080/foo/bar") {
    accept 'application/json'
}
HttpClientResponse response = p.get()
...
assert client.verify()
assert response.status == HttpStatus.OK
assert response.json.title == "Hello"

2.6. Configuration

The client can be configured with the Configuration trait and the DefaultConfiguration implementation class.

Typically for production deployments that use HTTPS you will need to configure the sslTrustManagerFactory using your own certificate.

The proxy property of the Configuration trait allows you to configure an HTTP or SOCKS proxy.

For proxy authentication set the http.proxyUser and http.proxyPassword system properties (or the equivalents for SOCKS)

2.7. Usage within Grails

Within Grails 3 you typically want to configure the client as a Spring bean within your Application class' doWithSpring method:

import grails.http.client.*
...
@Override
Closure doWithSpring() {{->
    httpBuilder(AsyncHttpBuilder)
}}

If you need to alter the configuration you can do so with the DefaultConfiguration class:

import grails.http.client.*
...
@Override
Closure doWithSpring() {{->
    def config = new DefaultConfiguration(proxy:..)
    httpBuilder(AsyncHttpBuilder, config)
}}

Then within a controller you can easily obtain a reference and use Grails' asynchronous request processing to perform HTTP calls to an external web service:

import grails.http.client.*
import grails.async.*
import static grails.async.Promises.*
...
@Autowired
AsyncHttpBuilder client
...
def myAction() {
    Promise<String> promise = client.get("https://localhost:8080/foo/bar") {
        accept 'application/json'
    }.then { HttpClientResponse res ->
        return res.json.title
    }
    tasks title: promise
}