In the previous recipe, Downloading content from the Internet, we described a simple way of getting binary/textual content from a URL. In this recipe, we will present a method to execute HTTP GET
requests with more control over the returned data.
As a starting point, we will use again the same URL
class encountered in the previous recipe. This time we'll explore the openConnection
method of the URL
class in order to have more options for understanding the intricacies of the response returned by the remote server:
def url = new URL('http://groovy.codehaus.org/') def connection = url.openConnection() connection.requestMethod = 'GET' if (connection.responseCode == 200) { println connection.content.text println connection.contentType println connection.lastModified connection.headerFields.each { println "> ${it}"} } else { println 'An error occurred: ' + connection.responseCode + ' ' + connection.responseMessage }
<!DOCTYPE html> <html> ... </html> text/html; charset=UTF-8 0 > null=[HTTP/1.1 200 OK] > Date=[Tue, 03 Sep 2013 13:03:13 GMT] > Content-Length=[39028] > Connection=[close] > Content-Type=[text/html; charset=UTF-8] > Server=[Resin/3.0.14]
The java.net.URLConnection
object, returned by the
openConnection
method, is convenient for getting hold of the additional response data such as, responseCode
, contentType
, or response headers
.
As you can notice, we set the requestMethod
property on the connection object to GET
value; but, in fact, it's not needed, because it is a default value anyway.
responseCode
is the Status Code Definition returned from the web server. For instance, a 404 status code, informs the client that the requested resource doesn't exist.
The connection object has the getContent
method, which is declared to return java.lang.Object
by the JDK API. The mechanism used by JDK to handle specific content types is out of scope of this recipe. However, the getContent
method typically returns an implementation of the InputStream
interface. That's why it is safe to retrieve the text
property, which is made available by Groovy on all classes that implement the InputStream
functionality.
An HTTP GET
request often requires additional parameters needed by the server or remote application. These parameters are propagated inside the URL through a query string:
http://groovy.codehaus.org/Project+Information?print=1
The previous URL passes to the server the following key/value information: print=1
, which is used to retrieve the Groovy project information page in printer-friendly format. In Groovy, the plain procedure to add a query string to a URL is just to use a string object. For example:
println ('http://groovy.codehaus.org/' + 'Project+Information?print=1').toURL().text
Query strings can be way lengthier than a single key/value entry. A Map
is the perfect data structure for representing the query string data. Let us see how a Map
can be converted into a query string:
def baseUrl = 'http://docs.codehaus.org/pages/editpage.action?' def params = [spaceKey: 'GROOVY', title: 'Project+Information'] def query = params.collect { k,v -> "$k=${URLEncoder.encode(v)}" }.join('&') println "${baseUrl}${query}"
The code yields the following output:
> http://docs.codehaus.org/pages/editpage.action?spaceKey=GROOVY&title=Project+Information
The code snippet that transforms a Map
into a query uses the collect
method of the Map
. It iterates through the Map
entries and executes a simple transformation closure returning a List. The closure simply encodes each parameter value using the java.net.URLEncoder
class and adds the =
sign between a parameter name and its content. Finally, the join
method is applied to the resulting collection to concatenate all entries into a single string using &
symbol.