Groovy - REST client without using libraries
Groovy supports HTTP out-of-the-box. Let's see how we can consume a REST API using Groovy without any libraries!
I chose an API I think can be quite useful, and requires no API key to get started with: the Yahoo! Weather API.
Here's how to send a HTTP GET request and print the response:
println new URL( "https://query.yahooapis.com/v1/public/yql?q=" +
URLEncoder.encode(
"select wind from weather.forecast where woeid in " +
"(select woeid from geo.places(1) where text='chicago, il')",
'UTF-8' ) ).text
Running this:
groovy weather.groovy
<?xml version="1.0" encoding="UTF-8"?>
<query xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" yahoo:count="1" yahoo:created="2015-09-30T21:04:53Z" yahoo:lang="en-US"><results><channel><yweather:wind xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0" chill="61" direction="50" speed="21"/></channel></results></query><!-- total: 43 -->
<!-- pprd1-node603-lh3.manhattan.bf1.yahoo.com -->
We did not specify which format to use, so we got the default format, XML.
Let's ask for JSON by using a different method which allows us to set some headers (you could add a query parameter format=json if you prefer):
def connection = new URL( "https://query.yahooapis.com/v1/public/yql?q=" +
URLEncoder.encode(
"select wind from weather.forecast where woeid in " + "(select woeid from geo.places(1) where text='chicago, il')",
'UTF-8' ) )
.openConnection() as HttpURLConnection
// set some headers
connection.setRequestProperty( 'User-Agent', 'groovy-2.4.4' )
connection.setRequestProperty( 'Accept', 'application/json' )
// get the response code - automatically sends the request
println connection.responseCode + ": " + connection.inputStream.text
Running:
groovy weather.groovy
200: {"query":{"count":1,"created":"2015-09-30T21:13:11Z","lang":"en-US","results":{"channel":{"wind":{"chill":"61","direction":"40","speed":"23"}}}}}
Great! Now we've got JSON and know how to set headers.
Next, we can let the user enter the location to query, so we can query lots of places without changing the source!
Also, change the query to select item, which contains lots of interesting information about the weather in the selected location.
def location = System.console().readLine( 'Location: ' )
def connection = new URL( "https://query.yahooapis.com/v1/public/yql?q=" +
URLEncoder.encode(
"select item " +
"from weather.forecast where woeid in " +
"(select woeid from geo.places(1) " +
"where text='$location')",
'UTF-8' ) )
.openConnection() as HttpURLConnection
// set some headers
connection.setRequestProperty( 'User-Agent', 'groovy-2.4.4' )
connection.setRequestProperty( 'Accept', 'application/json' )
// get the response code - automatically sends the request
println connection.responseCode + ": " + connection.inputStream.text
Running:
groovy weather.groovy
Location: Stockholm, Sweden
200: {"query":{"count":1,"created":"2015-09-30T21:19:42Z","lang":"en-US","results":{"channel":{"item":{"title":"Conditions for Stockholm, SE at 10:48 pm CEST","lat":"59.32","long":"18","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Stockholm__SE/*http://weather.yahoo.com/forecast/SWXX0031_f.html","pubDate":"Wed, 30 Sep 2015 10:48 pm CEST","condition":{"code":"3200","date":"Wed, 30 Sep 2015 10:48 pm CEST","temp":"50","text":"Unknown"},"description":"\n<img src=\"http://l.yimg.com/a/i/us/we/52/3200.gif\"/><br />\n<b>Current Conditions:</b><br />\nUnknown, 50 F<BR />\n<BR /><b>Forecast:</b><BR />\nWed - Partly Cloudy. High: 62 Low: 47<br />\nThu - Partly Cloudy. High: 64 Low: 49<br />\nFri - Sunny. High: 66 Low: 45<br />\nSat - Sunny. High: 59 Low: 45<br />\nSun - Mostly Sunny. High: 59 Low: 43<br />\n<br />\n<a href=\"http://us.rd.yahoo.com/dailynews/rss/weather/Stockholm__SE/*http://weather.yahoo.com/forecast/SWXX0031_f.html\">Full Forecast at Yahoo! Weather</a><BR/><BR/>\n(provided by <a href=\"http://www.weather.com\" >The Weather Channel</a>)<br/>\n","forecast":[{"code":"29","date":"30 Sep 2015","day":"Wed","high":"62","low":"47","text":"Partly Cloudy"},{"code":"30","date":"1 Oct 2015","day":"Thu","high":"64","low":"49","text":"Partly Cloudy"},{"code":"32","date":"2 Oct 2015","day":"Fri","high":"66","low":"45","text":"Sunny"},{"code":"32","date":"3 Oct 2015","day":"Sat","high":"59","low":"45","text":"Sunny"},{"code":"34","date":"4 Oct 2015","day":"Sun","high":"59","low":"43","text":"Mostly Sunny"}],"guid":{"isPermaLink":"false","content":"SWXX0031_2015_10_04_7_00_CEST"}}}}}}
JSON is nice, but this is still pretty unreadable... Let's parse the JSON content with Groovy's awesome JsonSlurper, so we can print a nice report.
import groovy.json.JsonSlurper
def location = System.console().readLine( 'Location: ' )
def connection = new URL( "https://query.yahooapis.com/v1/public/yql?q=" +
URLEncoder.encode(
"select item " +
"from weather.forecast where woeid in " +
"(select woeid from geo.places(1) " +
"where text='$location')",
'UTF-8' ) )
.openConnection() as HttpURLConnection
// set some headers
connection.setRequestProperty( 'User-Agent', 'groovy-2.4.4' )
connection.setRequestProperty( 'Accept', 'application/json' )
if ( connection.responseCode == 200 ) {
// get the JSON response
def json = connection.inputStream.withCloseable { inStream ->
new JsonSlurper().parse( inStream as InputStream )
}
// extract some data from the JSON, printing a report
def item = json.query.results.channel.item
println item.title
println "Temperature: ${item.condition?.temp}, Condition: ${item.condition?.text}"
// show some forecasts
println "Forecasts:"
item.forecast.each { f ->
println " * ${f.date} - Low: ${f.low}, High: ${f.high}, Condition: ${f.text}"
}
} else {
println connection.responseCode + ": " + connection.inputStream.text
}
Finally, running this:
groovy weather.groovy
Location: Stockholm, Sweden
Conditions for Stockholm, SE at 11:18 pm CEST
Temperature: 50, Condition: Partly Cloudy
Forecasts:
* 30 Sep 2015 - Low: 47, High: 62, Conditions: Partly Cloudy
* 1 Oct 2015 - Low: 49, High: 64, Conditions: Partly Cloudy
* 2 Oct 2015 - Low: 45, High: 66, Conditions: Sunny
* 3 Oct 2015 - Low: 45, High: 59, Conditions: Sunny
* 4 Oct 2015 - Low: 43, High: 59, Conditions: Mostly Sunny
And that's it! Very easy... to see more advanced things you can do with HttpURLConnection, check this StackOverflow answer (it's in Java, but you can use it all from Groovy, of course, without the mess)!
To get temperatures in degrees Centigrades, add the following text at the end of the main query: and u='c'
To make SSL connections work (for access using https without checking SSL certificates at all) add this to your Groovy script:
def sc = SSLContext.getInstance("SSL")
def trustAll = [getAcceptedIssuers: {}, checkClientTrusted: { a, b -> }, checkServerTrusted: { a, b -> }]
sc.init(null, [trustAll as X509TrustManager] as TrustManager[], new SecureRandom())
HttpsURLConnection.defaultSSLSocketFactory = sc.socketFactory
Just for reference, here's the full, formatted JSON response we got from the last couple of requests:
{
"query": {
"count": 1,
"created": "2015-09-30T21:19:42Z",
"lang": "en-US",
"results": {
"channel": {
"item": {
"title": "Conditions for Stockholm, SE at 10:48 pm CEST",
"lat": "59.32",
"long": "18",
"link": "http://us.rd.yahoo.com/dailynews/rss/weather/Stockholm__SE/*http://weather.yahoo.com/forecast/SWXX0031_f.html",
"pubDate": "Wed, 30 Sep 2015 10:48 pm CEST",
"condition": {
"code": "3200",
"date": "Wed, 30 Sep 2015 10:48 pm CEST",
"temp": "50",
"text": "Unknown"
},
"description": "\n<img src=\"http://l.yimg.com/a/i/us/we/52/3200.gif\"/><br />\n<b>Current Conditions:</b><br />\nUnknown, 50 F<BR />\n<BR /><b>Forecast:</b><BR />\nWed - Partly Cloudy. High: 62 Low: 47<br />\nThu - Partly Cloudy. High: 64 Low: 49<br />\nFri - Sunny. High: 66 Low: 45<br />\nSat - Sunny. High: 59 Low: 45<br />\nSun - Mostly Sunny. High: 59 Low: 43<br />\n<br />\n<a href=\"http://us.rd.yahoo.com/dailynews/rss/weather/Stockholm__SE/*http://weather.yahoo.com/forecast/SWXX0031_f.html\">Full Forecast at Yahoo! Weather</a><BR/><BR/>\n(provided by <a href=\"http://www.weather.com\" >The Weather Channel</a>)<br/>\n",
"forecast": [
{
"code": "29",
"date": "30 Sep 2015",
"day": "Wed",
"high": "62",
"low": "47",
"text": "Partly Cloudy"
},
{
"code": "30",
"date": "1 Oct 2015",
"day": "Thu",
"high": "64",
"low": "49",
"text": "Partly Cloudy"
},
{
"code": "32",
"date": "2 Oct 2015",
"day": "Fri",
"high": "66",
"low": "45",
"text": "Sunny"
},
{
"code": "32",
"date": "3 Oct 2015",
"day": "Sat",
"high": "59",
"low": "45",
"text": "Sunny"
},
{
"code": "34",
"date": "4 Oct 2015",
"day": "Sun",
"high": "59",
"low": "43",
"text": "Mostly Sunny"
}
],
"guid": {
"isPermaLink": "false",
"content": "SWXX0031_2015_10_04_7_00_CEST"
}
}
}
}
}
}