Loading...

June 15, 2016

Ratpacked: Use TestHttpClient For External HTTP Services

Ratpack has a very useful class: TestHttpClient. This is a blocking HTTP client that we normally use for testing our Ratpack applications. For example we use MainClassApplicationUnderTest or GroovyRatpackMainApplicationUnderTest in a test and invoke the getHttpClient method to get an instance of TestHttpClient. The class has a lot of useful methods to make HTTP requests with a nice DSL. TestHttpClient is also very useful as a standalone HTTP client in other applications.

Suppose we have a piece of code that needs to access MapQuest Open Platform Web Services to get location details for a given combination of longitude and latitude values. In the constructor we create an instance of the interface ApplicationUnderTest. We then can use the getHttpClient method of ApplicationUnderTest to get a TestHttpClient instance:

// File: src/main/groovy/mrhaki/geocode/GeocodeService.groovy
package mrhaki.geocode

import groovy.json.JsonSlurper
import ratpack.http.client.ReceivedResponse
import ratpack.test.ApplicationUnderTest
import ratpack.test.http.TestHttpClient

class GeocodeService {

    private final ApplicationUnderTest mapQuestApi
    private final GeocodeConfig config

    GeocodeService(final GeocodeConfig config) {
        this.config = config
        
        // Create ApplicationUnderTest using a Closure,
        // which returns the URI of our external HTTP service.
        // The ApplicationUnderTest interface only 
        // has one method (URI getAddress()), 
        // so we can use a Closure to implement the interface.
        mapQuestApi = { config.uri.toURI() }
    }

    Location getLocation(final Double latitude, final Double longitude) {
        // Create a blocking HttpClient with the base
        // URI from ApplicationUnderTest.
        final TestHttpClient httpClient = mapQuestApi.httpClient

        // Request location details for given latitude and longitude
        // and set the application key.
        httpClient.params { paramBuilder ->
            paramBuilder.put 'key', config.apiKey
            paramBuilder.put 'location', [latitude, longitude].join(',')
        }
        
        // Use get method to get a response from the HTTP service.
        final ReceivedResponse response = httpClient.get('geocoding/v1/reverse') 
        
        // Transform JSON result and
        // find location specific details in the response.
        final jsonResponse = new JsonSlurper().parseText(response.body.text)
        final location = jsonResponse.results[0].locations[0]
        
        // Create new Location object.
        new Location(street: location.street, city: location.adminArea5)
    }
    
}

The host name and key we need to make a request are set via the GeocodeConfig class:

// File: src/main/groovy/mrhaki/geocode/GeocodeConfig.groovy
package mrhaki.geocode

class GeocodeConfig {
    String apiKey
    String uri
}

And finally a simple POGO to store the location details:

// File: src/main/groovy/mrhaki/geocode/Location.groovy
package mrhaki.geocode

import groovy.transform.Immutable

@Immutable
class Location {
    String street
    String city
}

In our project we only have to add a dependency on io.ratpack:ratpack-test:

// File: build.gradle
...
dependencies {
    ...
    compile group: 'io.ratpack', name: 'ratpack-test', version: '1.3.3'
    ...
}
...

Written with Ratpack 1.3.3.