Skip to main content
Skip table of contents

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:

CODE
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:

CODE
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:

CODE
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:

CODE
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:

CODE
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:

CODE
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 or Accept headers

  • data 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:

CODE
    /**
     * 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:

CODE
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.

CODE
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:

CODE
    /**
     * 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:

CODE
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:

CODE
    /**
     * 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:

CODE
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:

CODE
    /**
     * 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:

CODE
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

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:

CODE
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.

CODE
    /**
     * 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:

CODE
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.

CODE
    /**
     * 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:

CODE
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:

CODE
    /**
     * @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.

CODE
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.

CODE
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 client

  • via 2 convenience methods directly exposed on the Groovy HTTP client:

    • basicAuth, to perform HTTP basic authentication

    • header, 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:

CODE
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:

CODE
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):

CODE
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:

CODE
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
groovy.client.rest.http.keyStorePKCS12

Secret

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
groovy.client.rest.http.trustStorePEM

String

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.

CODE
/**
 * 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.

CODE
/**
 * 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_ENCBINARY.

Those are convenient shortcuts to set well-known Content-Type values.

Response API

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.

CODE
/**
 * 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();

}

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.