Skip to content
rboy1 edited this page Sep 13, 2019 · 9 revisions

RESTClient is an extension of HTTPBuilder, which makes a few concessions in HTTPBuilder's flexibility in order to make REST operations as simple as possible.

Concessions:?

RESTClient makes great use of the automatic content-type parsing and encoding which makes working with XML and JSON extremely easy, both in the request and response side. It also adds some additional convenience methods for response header parsing.

The main advantages of RESTClient are:

  1. RESTClient has convenience methods for get, put post delete, head
  2. The response data is always parsed and buffered in-memory
  3. The returned HttpResponseDecorator instance gives convenient access to headers and the parsed response data
  4. No user-defined closure is needed

Examples

All of these examples use the Twitter REST API.

Test a URL using the HEAD method

@Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7')
@Grab('oauth.signpost:signpost-core:1.2.1.2')
@Grab('oauth.signpost:signpost-commonshttp4:1.2.1.2')
 
import groovyx.net.http.RESTClient
import static groovyx.net.http.ContentType.*
 
def twitter = new RESTClient( 'https://api.twitter.com/1.1/statuses/' )
// twitter auth omitted
 
try { // expect an exception from a 404 response:
    twitter.head path: 'public_timeline'
    assert false, 'Expected exception'
}
// The exception is used for flow control but has access to the response as well:
catch( ex ) { assert ex.response.status == 404 }
 
assert twitter.head( path: 'home_timeline.json' ).status == 200

The above example takes advantage of HTTPBuilder's default failure handler, which will cause an exception to be thrown for any 'failed' response. That exception will still allow access to details of the response (e.g. the response status or message).

GET our friends' timeline

def resp = twitter.get( path: 'home_timeline.json' )
def data = resp['reader']
assert resp.status == 200
assert resp.contentType == JSON.toString()
assert ( data instanceof List )
assert data.size() > 0

All request parameters are defined here.

The resp field in the above example is an instance of HttpResponseDecorator. Calling resp.getData() returns NULL, the data is available in the reader key. This is the same parsed response that you would get passed to HTTPBuilder's response handler closure, but it is always buffered in-memory and the response stream is automatically closed. The data offers the standard Java Map interface, i.e. .keySet() lists the top-level keys, and get("keyname","alternate_value") returns the value if defined or alternate if undef.

POST a status update to Twitter!

def msg = "I'm using HTTPBuilder's RESTClient on ${new Date()}"
 
def resp = twitter.post(
        path: 'update.json',
        body: [ status: msg, source: 'httpbuilder' ],
        requestContentType: URLENC )
 
assert resp.status == 200
assert resp.headers.Status
assert resp['reader'].text == msg
 
def postID = resp['reader'].id

Note that the above example is posting the request data as application/x-www-form-urlencoded. (The twitter API doesn't support XML or JSON POST requests.) For this reason, a requestContentType parameter must be specified in order to identify how the request body should be serialized.

Since we never set a default content-type on the RESTClient instance or pass a contentType argument in this request, RESTClient will put Accept: */* in the request header, and parse the response based on whatever is given in the response content-type header. So because Twitter correctly identifies its response as application/json, it will automatically be parsed by the default JSON parser.

Now DELETE that post

resp = twitter.delete( path: "destroy/${postID}.json" )
assert resp.status == 200
assert resp['reader'].id == postID
println "Test tweet ID ${resp['reader'].id} was deleted."
Clone this wiki locally