Groovy HTTP Client
Introduction
This guide describes the usage of the HTTP client in Groovy scripts.
The reader is supposed familiar with the Groovy syntax, including the notion of "closure".
The HTTP client is a tool available in Memority Groovy scripts. It enables to craft and send HTTP requests from Groovy scripts, but with some restrictions, namely regarding the list of allowed target IPs/hostnames.
HTTP Client Configuration
The Groovy HTTP Client configuration is performed per tenant using Settings under the groovy.client.rest.http
prefix. It is also possible to configure several HTTP clients using different settings, for custom needs (such as X509 client authentication typically).
The settings include configuration for low-level parameters such as:
connection timeouts
connection pool size
SSL trust store and key store
Some Settings examples:
groovy.client.rest.http.connectTimeoutMs # default connection timeout in milliseconds
groovy.client.rest.http.connectionPoolSize # default connection pool size
groovy.client.rest.http.forName.AD.connectTimeoutMs # specific connection timeout to use when connecting using client named 'AD'
groovy.client.rest.http.forName.AD.keyStorePKCS12 # PKCS12 data to use when connecting using client named 'AD'
If no Setting is available for a requested client name, then the default Settings are used instead.
HTTP Client Quick Glance
This section provides some simple examples of the usage of the Groovy HTTP client.
The complete API is provided in appendix.
All HTTP verbs are available through lower-cased methods named after them, such as get(String url)
, post(String url)
, etc.
A basic HTTP GET looks like:
try {
HTTP.get 'https://server.acme.tld
LOG.info("Success!")
} catch (HttpException e) {
LOG.error("Error code: " + e.statusCode)
}
// Produces: GET https://server.acme.tld
Another GET, but with HTTP parameters:
HTTP.get 'https://server.acme.tld' { queryParams k1:['v1','v2'],k3:'v3',k4:'v4' }
// Produces: GET https://server.acme.tld?k1=v1&k1=v2&k3=v3&k4=v4
A POST with form parameters:
HTTP.post 'https://server.acme.tld' { formParams k1:['v1','v2'],k3:'v3',k4:'v4' }
// Produces: POST https://server.acme.tld with a body of URL-encoded form parameters k1=v1&k1=v2&k3=v3&k4=v4
An authenticated GET request, using Basic HTTP authentication and as specific client name:
HTTP.get 'https://server.acme.tld' { clientName 'AD' basicAuth usernamePassword('myCredentials') }
// Produces a request with the Authorization: Basic header set. The 'myCredentials' string references Settings of type CredentialSetting
POSTing form parameters with basic HTTP authentication gives:
HTTP.post 'https://server.acme.tld' {
basicAuth 'myCredentials'
formParams k1:['v1','v2'],k3:'v3',k4:'v4'
}
A call to the HTTP client returns an object of type Response
, whose usage is detailed later in this guide.
Constructing the HTTP Request
An HTTP request comprises several aspects:
it targets an URL which may include parameters
it is composed of headers and a body (all are optional)
some headers have a specific meaning, such as the
Content-Type
orAccept
headersdata is sent encoded, using a charset
it can include handling "Closures" to react to certain HTTP responses
The Groovy HTTP client offers a syntax to craft an HTTP request taking all those aspects into account.
Constructing the Request URL Parameters
Several methods are available to control the URL parameters. They are listed below:
/**
* Add all the given query string parameters to the request URL, encoded with the default UTF-8 charset if "queryEncoding" was never called.
*/
queryParams(Map... queryParams);
/**
* Set the encoding to be used by subsequent calls to "queryParams". The default is UTF-8.
*/
queryEncoding(String encoding);
Example:
HTTP.get('https://server.acme.tld') {
queryEncoding 'ISO-8859-1'
queryParams param1:'value1', param2:['value2', 'value3']
}
Configuring the Client Name
The name of the client to use is configured at the request level. If there are no specific configuration parameters for this client, the defaults are used.
HTTP.get('https://server.acme.tld') {
clientName 'AD'
}
Constructing the Request Headers
Several methods are available to control the request headers. They are listed below:
/**
* Add free-form headers to the request. The {@code Map} value can be a single value or a list of values.
* Example: headers h1:['v1','v2'],h3:'v3',h4:'v4'
*/
headers(Map... headers)
/**
* A free-form Content-Type header, that may end with ";charset=..." for "text" requests.
*/
contentType(String contentType);
/**
* Set the request Content-Type header, augmented with the given charset parameter (such as "text/plain;charset=UTF-8").
* The ContentType argument is an enumeration containing the following elements: JSON, XML, TEXT, HTML, FORM_URL_ENC, BINARY.
* The charset is ignored for non-text types, i.e. the FORM_URL_ENC and BINARY types.
*/
contentType(ContentType contentType, String charset);
/**
* Set the Accept header with the given media types.
*/
accept(List<String> mediaTypes);
/**
* Set the Accept header to "*/*"
*/
acceptAll();
Example:
HTTP.post('https://server.acme.tld') {
contentType ContentType.TEXT, 'ISO-8859-1'
acceptAll()
// The request body is constructed below, see next section...
}
Constructing the Request Body
Several methods are available to control the request body. They are listed below:
/**
* JSON request body (always UTF-8).
* Automatically set the {@code Content-Type} header to "application/json;charset=UTF-8" if not already set.
*/
RequestBuilder json(Object json);
/**
* Text request body, encoded with the given charset
* Automatically set the {@code Content-Type} header to "text/plain;charset=charset-arg" if not already set.
*/
RequestBuilder text(String text, String charset);
/**
* Text request body, encoded with the charset parameter of the {@code Content-Type header}.
* If no charset parameter was provided with the {@code Content-Type header}, the default UTF-8 charset is used.
* Automatically set the {@code Content-Type} header to "text/plain;charset=UTF-8" if not already set.
*/
RequestBuilder text(String text);
/**
* Add all the given form parameters to the request body, encoded by default with the UTF-8 charset
* if {@link #formEncoding(String)} (String)} was never called.
* Automatically set the {@code Content-Type} header to "application/x-www-form-urlencoded" if not already set.
*/
RequestBuilder formParams(Map... formParams);
/**
* Set the encoding to be used by subsequent calls to {@link #formParams(Map...)}.
* The default is UTF-8.
*/
RequestBuilder formEncoding(String encoding);
/**
* Automatically set the {@code Content-Type} header to "multipart/form-data" if not already set, and adds a "file"
* part.
*
* @param partName the part name
* @param fileName the file name (may be null)
* @param data the file content
* @param contentType the part content type (may be null, defaults to {@code application/octet-stream})
* @param charset the part charset (may be null, in which case it will not appear in this part content type)
*/
RequestBuilder multipartFormData(String partName, String fileName, byte[] data, String contentType, String charset);
/**
* Same as {@link #multipartFormData(String, String, byte[], String, String) #multipartFormData(partName, fileName, data, contentType, null}
*/
RequestBuilder multipartFormData(String partName, String fileName, byte[] data, String contentType);
/**
* Same as {@link #multipartFormData(String, String, byte[], String, String) #multipartFormData(partName, null, data, contentType, null}
*/
RequestBuilder multipartFormData(String partName, byte[] data, String contentType);
/**
* Same as {@link #multipartFormData(String, String, byte[], String, String) #multipartFormData(partName, null, data, contentType, charset}
*/
RequestBuilder multipartFormData(String partName, byte[] data, String contentType, String charset);
/**
* Automatically set the {@code Content-Type} header to "multipart/form-data" if not already set, and adds a "string"
* part.
*
* @param partName the part name
* @param data the part content
* @param charset the part charset (may be null, defaults to UTF-8)
*/
RequestBuilder multipartFormData(String partName, String data, String charset);
/**
* Same as {@link #multipartFormData(String, String, String) #multipartFormData(partName, data, null)}
*/
RequestBuilder multipartFormData(String partName, String data);
/**
* Raw request body.
* Automatically set the {@code Content-Type} header to "application/octet-stream" if not already set.
*/
RequestBuilder bytes(byte[] bytes);
Example:
HTTP.post('https://server.acme.tld') {
json firstName: 'John', lastName: 'Doe'
}
HTTP.post('https://server.acme.tld') {
text 'Hello World'
}
HTTP.post('https://server.acme.tld') {
formEncoding 'ISO-8859-1'
formParams param1:'value1', param2:['value2', 'value3']
}
Configuring the Request Event Handlers
Several methods are available to add Closures that will be executed when the Response status code has certain values:
/**
* Configure a closure to be called if the response status code is 2xx. The closure is executed with the {@link Response}
* object as its sole argument.
*/
onSuccess(Closure closure);
/**
* Configure a closure to be called if the response status code is 3xx. The closure is executed with the {@link Response}
* object as its sole argument.
*/
onRedirect(Closure closure);
/**
* Configure a closure to be called if the response status code is 4xx or 5xx. The closure is executed with the {@link Response}
* object as its sole argument.
*/
onError(Closure closure);
/**
* Configure a closure to be called if the response status code is 4xx. The closure is executed with the {@link Response}
* object as its sole argument.
*/
onClientError(Closure closure);
/**
* Configure a closure to be called if the response status code is 5xx. The closure is executed with the {@link Response}
* object as its sole argument.
*/
onServerError(Closure closure);
/**
* Configure a closure to be called if the response status code is the one passed as argument. The closure is executed with the {@link Response}
* object as its sole argument.
*/
onStatusCode(int code, Closure closure);
The Response
itself is passed to all the Closure
arguments of the various onXXX(closure)
methods, it is accessible in closure's code through the it
operator, such as it.code
to obtain the response's HTTP status code (see examples below).
Example:
HTTP.get('https://server.acme.tld/john.doe') {
onSuccess { LOG.info("Successfully got John Doe: " + it.text) }
onError { LOG.error("Error while getting John Doe (code={}, msg={})", it.statusCode, it.text) }
}
HTTP.post('https://server.acme.tld') {
text 'Hello World'
onStatusCode 422, { r -> LOG.error("Invalid text posted!! " + r.text) }
}
Reading the HTTP Response
A call to the HTTP client returns an object of type Response
, whose properties and methods are detailed in this section.
An HTTP response comprises several aspects:
it has a numeric status code (200 for OK)
it is composed of headers and a body (all are optional)
data is decoded using the response's charset
The Groovy HTTP client offers a syntax to read an HTTP response, taking all those aspects into account.
Reading the Response Status Code
/**
* The response status code, such as 200.
*/
int getStatusCode();
/**
* Return true if the response status code starts with '2'.
*/
boolean isSuccess();
/**
* Return true if the response status code starts with '4'.
*/
boolean isClientError();
/**
* Return true if the response status code starts with '5'.
*/
boolean isServerError();
/**
* Return true if the response status code starts with '4' or '5'.
*/
boolean isError();
/**
* Return true if the response status code starts with '3'.
*/
boolean isRedirect();
Several methods are available to read the response's status code. They are listed below.
Example:
Response response = HTTP.get 'https://server.acme.tld'
LOG.info response.statusCode
Reading the Response Headers
Several methods are available to read the response's headers. They are listed below.
/**
* The raw response headers, including those mentioned below.
*/
Map<String, List<String>> headers;
/**
* The Content-Type header, media type only. Additional parameters such as "charset" are not included.
*/
String contentType;
/**
* The value of the Content-Encoding header, such as "gzip" or "deflate".
*/
String contentEncoding;
/**
* The value of the Content-Length header.
*/
int contentLength;
/**
* Set for a text response only, such as JSON or plain text. It is extracted from the Content-Type header.
*/
private String charset;
/**
* The value of the Accept header.
*/
private String accept;
Example:
Response response = HTTP.get 'https://server.acme.tld'
System.out.println 'Response Content-Type: ' + response.contentType
Reading the Response Body
Several methods are available to read the response's body. They are listed below.
/**
* The raw response body.
*/
byte[] body;
/**
* JSON body, set when the Content-Type header is "application/json".
*/
Object json;
/**
* XML body, set when the Content-Type header is "application/xml".
*/
String xml;
/**
* Text body, set when the Content-Type header is "text/plain".
*/
String text;
/**
* HTML body, set when the Content-Type header is "text/html".
*/
String html;
Example:
Response response = HTTP.get 'https://server.acme.tld'
System.out.println 'Response JSON body: ' + response.json
Handling Errors
When performing an HTTP request, an HttpException
is raised if the Response
status code is not in the 2xx range. If left uncaught, this will make the whole Groovy script fail. In some context, it might be possible to react to an error and apply countermeasures or alternatives.
The specific HttpException
is a simple container for the received Response
, and provides the following methods:
/**
* @return the HTTP status code of the received response.
*/
int getStatusCode();
/**
* @return the received response
*/
Response getResponse();
/**
* @return <code>true</code> if the status code is a REDIRECT (3xx), <code>false</code> otherwise
*/
boolean is3xxRedirection();
/**
* @return <code>true</code> if the status code is a CLIENT ERROR (4xx), <code>false</code> otherwise
*/
boolean is4xxClientError();
/**
* @return <code>true</code> if the status code is a SERVER ERROR (5xx), <code>false</code> otherwise
*/
boolean is5xxServerError();
Using Try-Catch
The best way to catch errors when performing an HTTP request is probably using a try ... catch
construct. This let one control the program flow more easily.
Response response;
try {
response = HTTP.get 'https://server.acme.tld' { queryParams id:'A2333' }
} catch (HttpException e) {
if (e.statusCode == 422) {
// Bad request, probably uses old API with 'objectId' query param
response = HTTP.get 'https://server.acme.tld' { queryParams objectId:'A2333' }
}
}
Using Error Handlers
An alternative method is to use error handling Closures set on the request. However, this method is better suited for logging or manipulating other variables that will control the flow.
When a handler Closure exist for a given status code (or series or status codes), then no HttpException
is thrown.
successful = true
response = HTTP.get 'https://server.acme.tld' {
queryParams id:'A2333'
onError { LOG.error("Received an error: " + it.text) && successful = false }
}
if (successful) {
// do stuff
} else {
// do alternative stuff
}
Authenticating an HTTP Request
Most of the time HTTP requests need to be authenticated. Authentication schemes often involve secrets, such as the Basic authentication scheme, whose Authorization
header includes a username and a password.
Secrets are securely stored as Memority "Settings", and accessible from Groovy scripts via mechanisms described in this section.
All secrets Settings accessible from Groovy scripts must be prefixed by a Settings key, whose default value is api.vault
. This prefix is automatically prepended to secret identifiers mentioned in Groovy scripts. For example, if a Groovy script requests a secret identified by "ACME-api-key", then a SecretSetting
with key api.vault.ACME-api-key
is fetched. This has several advantages:
security: Groovy scripts cannot freely access any secret
ease of use: it is easier to reference a secret by a short identifier such as "ACME-api-key" rather than "api.vault.ACME-api-key"
This prefix is configurable via the toolkit.addons.settings.api-vault-prefix
property.
The setting must be set in BUM settings.
Two kinds of access are possible:
via the
VAULT
variable bound to Groovy scripts, enabling to retrieve secrets and use them with the Groovy HTTP clientvia 2 convenience methods directly exposed on the Groovy HTTP client:
basicAuth
, to perform HTTP basic authenticationheader
, to add a secret header value to the request
Retrieving Secrets via VAULT
In the examples below, ACME-api-key
and ACME-user
are suffixes of Setting keys whose values are of type SecretSetting
and CredentialSetting
respectively. By default, the prefix key of all secret accessible from Groovy scripts is api.vault
.
It is more convenient to access secrets using a simple suffix rather than a full Setting key path, such as api.vault.ACME-api-key
. The Setting key prefix (api.vault
by default) is configurable on a per-application basis, via the property toolkit.addons.settings.api-vault-prefix
.
Example of secrets retrieval using VAULT
:
def secret = VAULT.secret('ACME-api-key')
// do something with 'secret'...
UsernamePasswordCredentials credentials = VAULT.usernamePasswordCredentials('ACME-user')
def username = credentials.username
def password = credentials.password
// do something with 'username' and 'password'...
Basic HTTP Authentication
Basic HTTP Authentication is supported by the Groovy HTTP Client, via the method basicAuth
, which can by used in 2 ways:
by providing a login and a password (not recommended!)
by providing a reference to a
CredentialSetting
(recommended)
Example of basic HTTP authentication by directly providing a login/password:
HTTP.get('https://server.acme.tld') { basicAuth('myUsername', 'myPassword') }
In this example, myUsername
and myPassword
are hard-coded values. This is not recommended, since the password is stored as plain text in the Groovy script. It is better to use a reference to a CredentialSetting
, see below.
Example of basic HTTP authentication by Setting key (recommended):
HTTP.get('https://server.acme.tld') { basicAuth( usernamePassword('ACME-user') ) }
As mentioned above, ACME-user
is the suffix of a Setting key of type CredentialSetting
.
Custom Headers Authentication
Some custom authentication schemes may expect a secret in the request headers. The header
and secret
methods help achieve this.
Example of a header whose value is a secret:
HTTP.get('https://server.acme.tld') { header('x-api-key', secret('ACME-api-key') ) }
// 'ACME-api-key' is a secret name that will be automatically resolved to the actual secret and injected in the header
As mentioned above, ACME-api-key
is the suffix of a Setting key of type SecretSetting
.
X509 Client Authentication
X509 client authentication is configured at the HTTP Client level (not at the request level). To use specific SSL parameters for various HTTP calls, then a client must be configured for each and used explicitly.
There are two Settings that intervene in configuring the X509 Client Authentication:
Setting (default) | Type | Description |
---|---|---|
CODE
|
| This contains the key and certificate to use for the X509 client authentication, in the PKCS12 format. As the secret is already encrypted, the PCKS12 shall not be password protected. |
CODE
|
| This contains the chain of certificates that are trusted for this specific connection, in a PEM format. This may be left empty, in which case the standard trust chain for the current Tenant will be used. |
These settings would typically be set as client specific settings, under a prefix such as groovy.client.rest.http.forName.CLIENT_NAME.
An empty setting for a specific client name will override the default one, if set
Digest Access Authentication
Digest access authentication is not supported yet.
Bearer Authentication
Bearer authentication is not supported yet
TLS Trust Store
Per-tenant trust store is not supported yet.
Using a HTTP Proxy
The usage of a HTTP proxy is transparent. The proxy is configured at the infrastructure level, it cannot be explicitly configured with the Groovy HTTP client.
Appendix: API Reference
GroovyRestClient API
The GroovyRestClient
API is the main entry point of Groovy scripts. An instance of this class is available in Groovy scripts, via the context variable named HTTP
.
The Closure
argument is optional, it may be omitted for each method.
/**
* The main entry point of Groovy scripts, such as HTTP.get('https://server.acme.tld')
* The Closure argument is optional, it may be omitted for each method.
*/
public interface GroovyRestClient {
Response get(String url, Closure closure);
Response post(String url, Closure closure);
Response put(String url, Closure closure);
Response patch(String url, Closure closure);
Response delete(String url, Closure closure);
Response head(String url, Closure closure);
}
RequestBuilder API
All the methods of the RequestBuilder
API can be invoked from all the Closure
arguments of the above GroovyRestClient
methods.
/**
* The methods enabling to construct a HTTP request.
*/
public interface RequestBuilder {
/**
* Set the request {@code Content-Type} header, with the given charset parameter.
* The charset is also used to encode the text content set by the {@link #text(String)} method.
*/
RequestBuilder contentType(ContentType contentType, String charset);
/**
* Set the request {@code Content-Type} header with no charset param.
*/
RequestBuilder contentType(ContentType contentType);
/**
* A free-form {@code Content-Type} header, that may end with {@code ;charset=...} for "text" requests.
*/
RequestBuilder contentType(String contentType);
/**
* Add a header to the request. If the header is already present, the given value is appended (multi-valued header).
*/
RequestBuilder header(String headerName, Object headerValue);
/**
* Add all the given headers to the request. The {@code Map} value can be a single value or a list of values.
*/
RequestBuilder headers(Map... headers);
/**
* Set the {@code Accept} header with the given media types.
*/
RequestBuilder accept(List<String> mediaTypes);
RequestBuilder accept(String... mediaTypes);
/**
* Set the {@code Accept} header to "*/*"
*/
RequestBuilder acceptAll();
/**
* Add all the given query string parameters to the request URL, encoded with the default UTF-8 charset if
* {@link #queryEncoding(String)} (String)} was never called.
* The {@code Map} value can be a single value or a list of values.
*/
RequestBuilder queryParams(Map... queryParams);
/**
* Set the encoding to be used by subsequent calls to {@link #queryParams(Map...)}.
*/
RequestBuilder queryEncoding(String encoding);
/**
* JSON request body (always UTF-8).
* Automatically set the {@code Content-Type} header to "application/json;charset=UTF-8" if not already set.
*/
RequestBuilder json(Object json);
/**
* Text request body, encoded with the given charset
* Automatically set the {@code Content-Type} header to "text/plain;charset=charset-arg" if not already set.
*/
RequestBuilder text(String text, String charset);
/**
* Text request body, encoded with the charset parameter of the {@code Content-Type header}.
* If no charset parameter was provided with the {@code Content-Type header}, the default UTF-8 charset is used.
* Automatically set the {@code Content-Type} header to "text/plain;charset=UTF-8" if not already set.
*/
RequestBuilder text(String text);
/**
* Add all the given form parameters to the request body, encoded by default with the UTF-8 charset
* if {@link #formEncoding(String)} (String)} was never called.
* Automatically set the {@code Content-Type} header to "application/x-www-form-urlencoded" if not already set.
*/
RequestBuilder formParams(Map... formParams);
/**
* Set the encoding to be used by subsequent calls to {@link #formParams(Map...)}.
* The default is UTF-8.
*/
RequestBuilder formEncoding(String encoding);
/**
* Raw request body.
* Automatically set the {@code Content-Type} header to "application/octet-stream" if not already set.
*/
RequestBuilder bytes(byte[] bytes);
/**
* Set a {@link Vault} on this builder, so that subsequent calls to {@link #usernamePassword(String)}
* or {@link #secret(String)} can succeed.
*/
RequestBuilder vault(Vault vault);
/**
* Use the HTTP Basic authentication scheme by crafting the appropriate {@code Authorization} header with the ISO-8859-1 encoding.
*
* @param username the username to use
* @param password the password to use
*/
RequestBuilder basicAuth(String username, String password);
/**
* Use the HTTP Basic authentication scheme by crafting the appropriate {@code Authorization} header with the given encoding.
*
* @param username the username to use
* @param password the password to use
* @param encoding used to encode the username/password
*/
RequestBuilder basicAuth(String username, String password, String encoding);
/**
* Use the HTTP Basic authentication scheme by crafting the appropriate {@code Authorization} header with the ISO-8859-1 encoding.
*
* @param usernamePasswordRef a reference to the credentials to use as returned by the method {@link #usernamePassword(String)}
*/
RequestBuilder basicAuth(UsernamePasswordRef usernamePasswordRef);
/**
* Use the HTTP Basic authentication scheme by crafting the appropriate {@code Authorization} header with the given encoding.
*
* @param usernamePasswordRef a reference to the credentials to use as returned by the method {@link #usernamePassword(String)}
* @param encoding used to encode the username/password
*/
RequestBuilder basicAuth(UsernamePasswordRef usernamePasswordRef, String encoding);
/**
* Add to the request a header whose value is a secret. Useful to authenticate to a server expecting such a secret.
*
* @param headerName the name of the HTTP header
* @param secretRef a reference to the secret to use as returned by the method {@link #secret(String)}
* @throws UnsupportedOperationException if no {@link Vault} was set on this builder
*/
RequestBuilder header(String headerName, SecretRef secretRef);
/**
* Return a a reference to a secret from {@link Vault}, this reference can then be used in {@link #header(String, SecretRef)}
*
* @param secretRef a reference to the secret stored in a {@link Vault}
* @throws UnsupportedOperationException if no {@link Vault} was set on this builder
*/
SecretRef secret(String secretRef);
/**
* Return a reference to credentials from {@link Vault}, this reference can then be used in {@link #basicAuth(UsernamePasswordRef)}
*
* @param credentialsRef a reference to the credentials stored in a {@link Vault}
* @throws UnsupportedOperationException if no {@link Vault} was set on this builder
*/
UsernamePasswordRef usernamePassword(String credentialsRef);
/**
* Configure a closure to be called if the response status code is 2xx. The closure is executed with the {@link Response}
* object as its sole argument.
*
* @param closure the closure to execute on success
*/
RequestBuilder onSuccess(@ClosureParams(ResponseHint.class) Closure closure);
/**
* Configure a closure to be called if the response status code is 3xx. The closure is executed with the {@link Response}
* object as its sole argument.
*
* @param closure the closure to execute on redirect
*/
RequestBuilder onRedirect(@ClosureParams(ResponseHint.class) Closure closure);
/**
* Configure a closure to be called if the response status code is 4xx or 5xx. The closure is executed with the {@link Response}
* object as its sole argument.
*
* @param closure the closure to execute on error
*/
RequestBuilder onError(@ClosureParams(ResponseHint.class) Closure closure);
/**
* Configure a closure to be called if the response status code is 4xx. The closure is executed with the {@link Response}
* object as its sole argument.
*
* @param closure the closure to execute on client error
*/
RequestBuilder onClientError(@ClosureParams(ResponseHint.class) Closure closure);
/**
* Configure a closure to be called if the response status code is 5xx. The closure is executed with the {@link Response}
* object as its sole argument.
*
* @param closure the closure to execute on server error
*/
RequestBuilder onServerError(@ClosureParams(ResponseHint.class) Closure closure);
/**
* Configure a closure to be called if the response status code is the one passed as argument. The closure is executed with the {@link Response}
* object as its sole argument.
*
* @param closure the closure to execute on success
*/
RequestBuilder onStatusCode(int code, @ClosureParams(ResponseHint.class) Closure closure);
The ContentType
argument is an enumeration containing the following elements: JSON
, XML
, TEXT
, HTML
, FORM_URL_ENC
, BINARY
.
Those are convenient shortcuts to set well-known Content-Type
values.
Response API
A Response
object is returned by a call to get(String url)
, post(String url)
, etc.
The Response
's available fields and methods are listed below.
/**
* The response returned by a HTTP request.
*/
@Data
public class Response {
/**
* The response status code, such as 200.
*/
private final int statusCode;
/**
* The response headers.
*/
private final Map<String, List<String>> headers;
/**
* The response body, may be null.
*/
private final byte[] body;
/////// Fields extracted from the above raw data ///////
/**
* The {@code Content-Type} header, media type only. Additional parameters such as "charset" are not included.
*/
private String contentType;
/**
* The value of the {@code Content-Encoding} header, such as "gzip" or "deflate".
*/
private String contentEncoding;
/**
* The value of the {@code Content-Length} header.
*/
private int contentLength;
/**
* Set for a text response only, such as JSON or plain text. It is extracted from the {@code Content-Type} header.
*/
private String charset;
/**
* The value of the {@code Accept} header.
*/
private String accept;
/**
* Response body, set when the {@code Content-Type} header is "application/json".
*/
private Object json;
/**
* Response body, set when the {@code Content-Type} header is "application/xml".
*/
private String xml;
/**
* Response body, set when the {@code Content-Type} header is "text/plain".
*/
private String text;
/**
* Response body, set when the {@code Content-Type} header is "text/html".
*/
private String html;
/////// Methods ///////
public boolean isSuccess();
public boolean isError();
public boolean isRedirect();
public boolean isClientError();
public boolean isServerError();
}