Calling Web Services¶
SmartApps or device handlers may need to make calls to external web services. There are several APIs available to you to handle making these requests.
The various APIs are named for the underlying HTTP method they will use. httpGet()
makes an HTTP GET request, for example.
Important
Requests are limited to ten seconds. If the request takes longer than that, it will timeout.
The following methods are available for making HTTP requests. You can read more about each of them in the SmartApp API documentation.
Method | Description |
---|---|
httpDelete() | Executes an HTTP DELETE request |
httpGet() | Executes an HTTP GET request |
httpHead() | Executes an HTTP HEAD request |
httpPost() | Executes an HTTP POST request |
httpPostJson() | Executes an HTTP POST request with JSON Content-Type |
httpPutJson() | Executes an HTTP PUT request with JSON Content-Type |
Here’s a simple example of making an HTTP GET request:
def params = [
uri: "http://httpbin.org",
path: "/get"
]
try {
httpGet(params) { resp ->
resp.headers.each {
log.debug "${it.name} : ${it.value}"
}
log.debug "response contentType: ${resp.contentType}"
log.debug "response data: ${resp.data}"
}
} catch (e) {
log.error "something went wrong: $e"
}
Configuring The Request¶
The various APIs for making HTTP requests all accept a map of parameters that define various information about the request:
Parameter | Description |
---|---|
uri | Either a URI or URL of of the endpoint to make a request from. |
path | Request path that is merged with the URI. |
query | Map of URL query parameters. |
headers | Map of HTTP headers. |
contentType | Request content type and Accept header. |
requestContentType | Content type for the request, if it is different from the expected response content-type. |
body | Request body that will be encoded based on the given contentType. |
Note
Specifying a reqeustContentType
may override the default behavior of the various http API you are calling.
For example, httpPostJson()
sets the requestContentType
to "application/json"
by default.
Handling The Response¶
The HTTP APIs accept a closure that will be called with the response information from the reqeust.
The closure is passed an instance of a HttpResponseDecorator. You can inspect this object to get information about the response.
Here’s an example of getting various response information:
def params = [
uri: "http://httpbin.org",
path: "/get"
]
try {
httpGet(params) { resp ->
// iterate all the headers
// each header has a name and a value
resp.headers.each {
log.debug "${it.name} : ${it.value}"
}
// get an array of all headers with the specified key
def theHeaders = resp.getHeaders("Content-Length")
// get the contentType of the response
log.debug "response contentType: ${resp.contentType}"
// get the status code of the response
log.debug "response status code: ${resp.status}"
// get the data from the response body
log.debug "response data: ${resp.data}"
}
} catch (e) {
log.error "something went wrong: $e"
}
Tip
Any ‘failed’ response response will generate an exception, so you should wrap your calls in a try/catch block.
If the response returns JSON, data
will be in a map-like structure that allows you to easily access the response data:
def makeJSONWeatherRequest() {
def params = [
uri: 'http://api.openweathermap.org/data/2.5/',
path: 'weather',
contentType: 'application/json',
query: [q:'Minneapolis', mode: 'json']
]
try {
httpGet(params) {resp ->
log.debug "resp data: ${resp.data}"
log.debug "humidity: ${resp.data.main.humidity}"
}
} catch (e) {
log.error "error: $e"
}
}
The resp.data
from the request above would look like this (indented for readability):
resp data: [id:5037649, dt:1432752405, clouds:[all:0],
coord:[lon:-93.26, lat:44.98], wind:[speed:4.26, deg:233.507],
cod:200, sys:[message:0.012, sunset:1432777690, sunrise:1432722741,
country:US],
name:Minneapolis, base:stations,
weather:[[id:800, icon:01d, description:Sky is Clear, main:Clear]],
main:[humidity:73, pressure:993.79, temp_max:298.696, sea_level:1026.82,
temp_min:298.696, temp:298.696, grnd_level:993.79]]
We can easily get the humidity from this data structure as shown above:
resp.data.main.humidity
Try It Out¶
If you’re interested in experimenting with the various HTTP APIs, there are a few tools you can use to try out the APIs without signing up for any API keys.
You can use httpbin.org to test making simple requests. The httpGet()
example above uses it.
For testing POST requests, you can use PostCatcher. You can generate a target URL and then inspect the contents of the request. Here’s an example using httpPostJson():
def params = [
uri: "http://postcatcher.in/catchers/<yourUniquePath>",
body: [
param1: [subparam1: "subparam 1 value",
subparam2: "subparam2 value"],
param2: "param2 value"
]
]
try {
httpPostJson(params) { resp ->
resp.headers.each {
log.debug "${it.name} : ${it.value}"
}
log.debug "response contentType: ${resp. contentType}"
}
} catch (e) {
log.debug "something went wrong: $e"
}
See Also¶
A simple example using httpGet
that connects a SmartSense Temp/Humidity to your Weather Underground personal weather station can be found here.
You can browse some templates in the IDE that use the various HTTP APIs. The Ecobee Service Manager is an example that uses both httpGet()
and httpPost()
.