Content-Type Response Parsing

One of HTTPBuilder's strengths is its in-built ability to parse many content-types. If a response is text/xml it is automatically parsed by groovy.util.XmlSlurper. An application/json response will be parsed into a POGO object via Json-Lib, and a text/plain response will come back as a java.io.Reader. This is done by comparing the response's Content-Type header to entries in the current ParserRegistry instance.

You can see the default content-types handled by HTTPBuilder in the ParserRegistry class}.

If you want to override the automatic parsing (say, to get an XML response as a plain string) you can tell HTTPBuilder how it should try to parse the text. (This is also handy if a server is being dumb and serving HTML data as plain text, for instance.)

The contentType parameter tells HTTPBuilder how it should parse the response.

def http = new HTTPBuilder('http://ajax.googleapis.com')

http.request( Method.GET, ContentType.TEXT ) { req ->
  uri.path = '/ajax/services/search/web'
  uri.query = [ v:'1.0', q: 'Calvin and Hobbes' ]
  headers.Accept = 'application/json'

  response.success = { resp, reader ->
    println "Got response: ${resp.statusLine}"
    println "Content-Type: ${resp.headers.'Content-Type'}"
    print reader.text
  }
}

The contentType parameter also instructs HTTPBuilder to add an Accept header to the request for the specified content-type. Assuming we still want to get JSON data, but not parse it, the headers.Accept = ... line above overrides the automatic Accept: text/plain header that would otherwise be added by the ContentType.TEXT argument.

Now assume we always want to handle XML as plain text. (maybe you're passing it on to a SAX parser or something similar.) We can re-use the TEXT content-type handler by assigning it to the XML content-type in the ParserRegistry:

http.parser.'application/xml' = http.parser.'text/plain'

Now, any response that comes in with a Content-Type: application/xml header will be handled using the plain-text parser -- meaning it's simply returned as a reader.

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:

import au.com.bytecode.opencsv.CSVReader
import groovyx.net.http.ParserRegistry

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:

http.get( uri : 'http://somehost.com/contacts.csv',
                    contentType : 'text/csv' ) { resp, csv ->

        assert csv instanceof CSVReader
        // parse the csv stream here.
}

You can refer to IANA for a complete list of registered content-type names, but the most common are already handled in the ContentType enumeration.