Perform a simple HTTP GET and parse the response as a DOM object:

def http = new HTTPBuilder('')

def html = http.get( path : '/search', query : [q:'Groovy'] )

assert html instanceof GPathResult
assert html.HEAD.size() == 1
assert html.BODY.size() == 1

In the above example, we are making a request, and automatically parsing the HTML response based on the response's content-type header. The HTML stream is normalized (thanks to Neko, ) and then parsed by an XmlSlurper for easy DOM parsing.

Keep reading for more examples of how the HTTPBuilder can handle more complex request/ response logic, as well as parsing other content-types...

Next is another GET request, with custom response-handling logic that prints the response to System.out :

def http = new HTTPBuilder('')

http.get( path : '/search', 
          contentType : TEXT,
          query : [q:'Groovy'] ) { resp, reader ->
  println "response status: ${resp.statusLine}"
  println 'Response data: -----'
  System.out << reader
  println '\n--------------------'

Note that in this version, the closure is a response handler block that is only executed on a successful response. A failure response (i.e. status code of 400 or greater) is handled by the builder's default failure handler .

Additionally, we are telling HTTPBuilder to parse the response as ContentType.TEXT - which is built-in content-type handled by the default ParserRegistry to automatically create a Reader from the response data.

More Verbose (and Flexible) Request

This is a longer request form may be used for other HTTP methods, and also allows for response-code-specific handlers:

import static
import static

http.request(GET,TEXT) { req -> = '' // overrides default URL
  headers.'User-Agent' = 'Mozilla/5.0'
  response.success = { resp, reader ->
    println 'my response handler!'
    assert resp.statusLine.statusCode == 200
    println resp.statusLine
    System.out << reader // print response stream
  response.'404' = { resp ->  // fired only for a 401 (access denied) status code
    println 'Not found'

As mentioned above, you can also set a default "failure" response handler which is called for any status code > 399 that is not matched to a specific handler. Setting the value outside a request closure means it will apply to all future requests with this HTTPBuilder instance:

http.handler.'401' = { resp ->
  println "Access denied"

// Used for all other failure codes not handled by a code-specific handler:
http.handler.failure = { resp ->
  println "Unexpected failure: ${resp.statusLine}"

The Magic: Built-in Content-Type Parsing

In this example, a registered content-type parser recognizes the response content-type header, and automatically parses the response data into a JSON object before it is passed to the 'success' response handler closure.

import static
import static

http.request( '', GET, JSON ) {
  url.path = '/ajax/services/search/web'
  url.query = [ v:'1.0', q: 'Calvin and Hobbes' ]
  response.success = { resp, json ->
    assert json.size() == 3
    println "Query response: "
    json.responseData.results.each {
      println "  ${it.titleNoFormatting} : ${it.visibleUrl}"

Parser Resolution

By default, HTTPBuilder uses ContentType.ANY as the default content-type. This means the value of the request's Accept header is */* , and the response parser is determined based on the response content-type header value.

If any contentType is given (either in HTTPBuilder.setContentType(...) or as a request method parameter), the builder will attempt to parse the response using that content-type, regardless of what the server actually responds with.

Support for new Content Types

To add parsing for new content types, simply add a new entry to the builder's ParserRegistry . For example, to parse comma-separated-values using OpenCSV :


http.parser.'text/csv' = { resp ->
  return new CSVReader( new InputStreamReader( resp.entity.content,
                                ParserRegistry.getCharset( resp ) ) )

A CSVReader instance will then be passed as the second argument to the response handler. See IANA for a list of registered content-type names.


Probably the quickest way to debug is to turn on logging for HTTPBuilder and HttpClient. An example log4j configuration can be used to output headers and request/response body content.