Class RestClient

java.lang.Object
io.inversion.utils.RestClient

public class RestClient extends Object
An HttpClient wrapper designed specifically to run inside of an Inversion io.inversion.Action with some superpowers.

RestClient gives you easy or built in:

  • fluent asynchronous response handler api
  • automatic retry support
  • header forwarding w/ whitelists and blacklists
  • url query string param forwarding w/ whitelist and blacklists
  • lazy runtime host url construction through lookup of "${name}.url" in the environment
  • dynamic host url variables - any "${paramName}" tokens in the host url will be replaced with Chain.peek.getRequest().getUrl().getParam(paramName).
  • short circuit remote calls or transform Requests/Responses with a single override of doRequest(Request)

Transforming requests / responses

You can easily override the doRequest(Request) method to potentially short circuit calls or perform request/response transforms.

For example:


      protected RestClient client = new RestClient("myservice")
      {
          protected Response doRequest(Request request)
          {
              if(checkMyCondition(request))
              {
                  //-- short circuit the remote call "faking" a
                  //-- remote 200 response (the default status code for a Response)
                  return new Response(request.getUrl());
              }
              else
              {
                  doMyRequestTransformation(request);

                  Response response = super.getResponse(request);

                  doMyResponseTransformation(response);

                  return response;
              }
          }
      }

      client.get("/some/relative/path")
          .onSuccess(response -@gt; System.out.println("Success:" + res.toString()))
          .onFailure(response -@gt; System.out.println("Failure:" + res.toString()))
          .onResponse(response -@gt; System.out.println(res.getStatus()));


      //-- instead of using the success/failure callbacks as above
      //-- you can wait for the async process to complete by calling 'get()'

      FutureResponse future = client.post("/some/relative/path", new JSNode("hello", "world"));
      //-- request is asynchronously executing here

      //-- the call to get() blocks indefinitely until the async execution completes
      //-- the fact that this method is called 'get()' is not related to HTTP get.
      Response response = future.get();


      //-- now do whatever you want with the Response

 
  • Field Details

    • includeForwardHeaders

      protected final Set includeForwardHeaders
      Always forward these headers.
      See Also:
    • excludeForwardHeaders

      protected final Set excludeForwardHeaders
      Never forward these headers.
      See Also:
    • forcedHeaders

      protected final org.apache.commons.collections4.multimap.ArrayListValuedHashMap<String,String> forcedHeaders
      Headers that are always sent regardless of forwardHeaders, includeForwardHeaders and excludeForwardHeaders state.

      These headers will overwrite any caller supplied or forwarded header with the same key, not append to the value list.

      This list is initially empty.

    • includeParams

      protected final Set<String> includeParams
      Always forward these params.
      See Also:
    • excludeParams

      protected final Set<String> excludeParams
      Never forward these params.
      See Also:
    • requestListeners

      protected final List<RestClient.RequestListener> requestListeners
    • responseListeners

      protected final List<Consumer<Response>> responseListeners
    • name

      protected String name
      The RestClient name that will be for property decoding.
      See Also:
    • forwardHeaders

      protected boolean forwardHeaders
      Indicates the headers from the root inbound Request being handled on this Chain should be included on this request minus any excludeForwardHeaders.

      Default value is true.

    • url

      protected String url
      Optional base url that will be prepended to the url arg of any calls assuming that the url arg supplied is a relative path and not an absolute url.
    • useCompression

      protected boolean useCompression
      Indicates that a request body should be gzipped and the content-encoding header should be sent with value "gzip".

      Default value is true.

    • compressionMinSize

      protected int compressionMinSize
      If useCompression is true, anything over this size in bytes will be compressed.

      Default value is 1024.

    • forwardParams

      protected boolean forwardParams
      Indicates the params from the root inbound Request being handled on this Chain should be included on this request minus any blacklisted params.
    • executor

      protected RestClient.Executor executor
      The thread pool executor used to make asynchronous requests
    • retryMax

      protected int retryMax
      The default maximum number of times to retry a request

      The default value is zero meaning by default, failed requests will not be retried

    • retryTimeoutMin

      protected int retryTimeoutMin
      The length of time before the first retry.

      Incremental retries receive progressively more of a timeout up to retryTimeoutMax.

      See Also:
    • retryTimeoutMax

      protected int retryTimeoutMax
      The maximum amount of time to wait before a single retry.
      See Also:
    • socketTimeout

      protected int socketTimeout
      Parameter for default HttpClient configuration
      See Also:
      • RequestConfig.Builder.setSocketTimeout(int)
    • connectTimeout

      protected int connectTimeout
      Parameter for default HttpClient configuration
      See Also:
      • RequestConfig.Builder.setConnectTimeout(int)
    • requestTimeout

      protected int requestTimeout
      Parameter for default HttpClient configuration
      See Also:
      • RequestConfig.Builder.setConnectionRequestTimeout(int)
    • httpClient

      protected org.apache.http.client.HttpClient httpClient
      The underlying HttpClient use for all network comms.
    • threadsMax

      protected int threadsMax
      The number of background executor threads.

      A value < 1 will cause all tasks to execute synchronously on the calling thread meaning the FutureResponse will always be complete upon return.

      The default value is 5.

  • Constructor Details

    • RestClient

      public RestClient()
    • RestClient

      public RestClient(String name)
      Parameters:
      name - the prefix used to look up property values from the environment if they have not already been wired
  • Method Details

    • get

      public RestClient.FutureResponse get(String fullUrlOrRelativePath)
      Convenience overloading of call(String, String, Map, JSNode, int, ArrayListValuedHashMap) to perform a GET request.
      Parameters:
      fullUrlOrRelativePath - may be a full url or relative to the url property if set, can have a query string or not
      Returns:
      a FutureResponse that will asynchronously resolve to a Response
    • get

      public RestClient.FutureResponse get(String fullUrlOrRelativePath, String queryString)
      Convenience overloading of call(String, String, Map, JSNode, int, ArrayListValuedHashMap) to perform a GET request.
      Parameters:
      fullUrlOrRelativePath - may be a full url or relative to the url property if set, can have a query string or not
      queryString - additional query string params in name=value@amp;name2=value2 style
      Returns:
      a FutureResponse that will asynchronously resolve to a Response
    • get

      public RestClient.FutureResponse get(String fullUrlOrRelativePath, Map<String,String> params)
      Convenience overloading of call(String, String, Map, JSNode, int, ArrayListValuedHashMap) to perform a GET request.
      Parameters:
      fullUrlOrRelativePath - may be a full url or relative to the url property if set, can have a query string or not
      params - query strings passed in as a map
      Returns:
      a FutureResponse that will asynchronously resolve to a Response
    • get

      public RestClient.FutureResponse get(String fullUrlOrRelativePath, String... queryStringNameValuePairs)
      Convenience overloading of call(String, String, Map, JSNode, int, ArrayListValuedHashMap) to perform a GET request.
      Parameters:
      fullUrlOrRelativePath - may be a full url or relative to the url property if set, can have a query string or not
      queryStringNameValuePairs - additional query string name/value pairs
      Returns:
      a FutureResponse that will asynchronously resolve to a Response
    • post

      public RestClient.FutureResponse post(String fullUrlOrRelativePath, JSNode body)
      Convenience overloading of call(String, String, Map, JSNode, int, ArrayListValuedHashMap) to perform a POST request.
      Parameters:
      fullUrlOrRelativePath - may be a full url or relative to the url property if set
      body - the optional JSON to post
      Returns:
      a FutureResponse that will asynchronously resolve to a Response
    • put

      public RestClient.FutureResponse put(String fullUrlOrRelativePath, JSNode body)
      Convenience overloading of call(String, String, Map, JSNode, int, ArrayListValuedHashMap) to perform a PUT request.
      Parameters:
      fullUrlOrRelativePath - may be a full url or relative to the url property if set
      body - the optional JSON to put
      Returns:
      a FutureResponse that will asynchronously resolve to a Response
    • patch

      public RestClient.FutureResponse patch(String fullUrlOrRelativePath, JSNode body)
      Convenience overloading of call(String, String, Map, JSNode, int, ArrayListValuedHashMap) to perform a PATCH request.
      Parameters:
      fullUrlOrRelativePath - may be a full url or relative to the url property if set
      body - the optional JSON patch
      Returns:
      a FutureResponse that will asynchronously resolve to a Response
    • delete

      public RestClient.FutureResponse delete(String fullUrlOrRelativePath)
      Convenience overloading of call(String, String, Map, JSNode, int, ArrayListValuedHashMap) to perform a DELETE request.
      Parameters:
      fullUrlOrRelativePath - may be a full url or relative to the url property if set
      Returns:
      a FutureResponse that will asynchronously resolve to a Response
    • call

      public RestClient.FutureResponse call(String method, String fullUrlOrRelativePath, Map<String,String> params, JSNode body, int retryMax, org.apache.commons.collections4.multimap.ArrayListValuedHashMap<String,String> headers)
      Makes an HTTP request.
      Parameters:
      method - the HTTP method to invoke
      fullUrlOrRelativePath - optional may be a full url or only additional relative path parts if the url property if set, may contain a query string
      params - optional additional query string params that will overwrite any that may be on url as composed from buildUrl(String)
      body - optional json body
      retryMax - how many times the client should retry if the Request is not successful, if less than zero then this.retriesMax is used
      headers - headers that will always be sent regardless of includeForwardHeaders, excludeForwardHeaders but may be overwritten by forcedHeaders
      Returns:
      a FutureResponse that will asynchronously resolve to a Response
    • call

      public RestClient.FutureResponse call(Request request)
      Executes the request as provided without modification.

      All of the other 'get/post/put/patch/delete/call' methods will construct a Request based on the configured properties of this RestClient and optionally the data in Request on the top of the Chain if operating inside an Engine.

      Those methods ultimately delegate to this method and no further modification of the Request is made from here out.

      Parameters:
      request -
      Returns:
    • buildRequest

      public Request buildRequest(String method, String fullUrlOrRelativePath, Map<String,String> params, JSNode body, org.apache.commons.collections4.multimap.ArrayListValuedHashMap<String,String> headers, int retryMax)
      Builds a request with the supplied information merged with the url, query param, and header options configured on this reset client and potentially pulled from the Chain request.
      Parameters:
      method - - the http method
      fullUrlOrRelativePath - - a full url or a relative path that will be appended to this.url
      params - - query params to pass
      body - - the request body to pass
      headers - - request headers to pass
      retryMax - - the number of times to retry this call if it fails.
      Returns:
      the configure request
    • doRequest

      protected Response doRequest(Request request)
      The work of executing the remote call is done here.

      Override this method to intercept the remote call and change anything about the Request or Response that you want.

      All of the Request url/header/param configuration has already been done on the Request.

      You don't need to do anything related to threading here. This method is already executing asynchronously within the Executor's thread pool. Simply handle/transform the Request/Response as desired. Simply returning a Response will cause the FutureResponse to transition to done and allow calls blocking on FutureResponse.get() to receive the Response.

      Overriding this method can be really helpful when you what your RestClient calling algorithm to say clean, hiding some of the Request/Response customization details or otherwise need to make sure Requests/Responses are always handled in a specific way.

      A typical override of this method might look like the following:

       protected RestClient client = new RestClient("myservice"){
      
        protected Response doRequest(Request request)
        {
            if(checkMyCondition(request))
            {
                //-- short circuit the remote call "faking" a
                //-- remote 200 response (the default status code for a Response)
                return new Response(request.getUrl());
            }
            else
            {
                doMyRequestTransformation(request);
      
                Response response = super.getResponse(request);
      
                doMyResponseTransformation(response);
      
                return response;
            }
        }
       }
       
      Parameters:
      request - the request to make
      Returns:
      a Response containing the server response data or error data. Will not be null.
    • onRequest

      public RestClient onRequest(RestClient.RequestListener requestListener)
    • onResponse

      public RestClient onResponse(Consumer<Response> responseListener)
    • computeTimeout

      protected long computeTimeout(Request request, Response response)
      Computes an incremental retry backoff time between retryTimeoutMin and retryTimeoutMax.

      You can override this to provide your own timeout policy.

      Parameters:
      request - the Request being made
      response - the Response being computed
      Returns:
      the number of milliseconds to wait before retrying the Request
    • shouldRetry

      protected boolean shouldRetry(Request request, Response response)
      Determines if the Request should be retried.

      You can override this to provide your own retry policy.

      The default algorithm will only retry if the Request is not successful due to a network error and the current request.retryCount is less than reqest.retryMax.

      Parameters:
      request - the Request being made
      response - the Response being computed
      Returns:
      true if this request should be retried
      See Also:
      • isNetworkException(Throwable)
    • buildHttpClient

      protected org.apache.http.client.HttpClient buildHttpClient() throws Exception
      Factory method for building an HttpClient if one was not configured via withHttpClient.

      The default HttpClient constructed here basically SSL cert and hostname verification assuming that you will be calling clients you control.

      If you need to adopt a tighter security posture just override this method or call withHttpClient(HttpClient) to supply your own HttpClient and security configuration.

      Use of this method is wrapped by getHttpClient() which controls concurrency so this method should not be called more than once per instance if an error is not thrown.

      Returns:
      an HttpClient that can be use to make concurrent asynchronous requests.
      Throws:
      Exception - if HttpClient construction fails
      See Also:
    • withUrl

      public RestClient withUrl(String url)
    • getForcedHeaders

      public org.apache.commons.collections4.multimap.ArrayListValuedHashMap<String,String> getForcedHeaders()
    • withForcedHeader

      public RestClient withForcedHeader(String name, String value)
    • withForcedHeaders

      public RestClient withForcedHeaders(String... headers)
    • withForwardedHeaders

      public RestClient withForwardedHeaders(boolean forwardHeaders)
    • withForwardedParams

      public RestClient withForwardedParams(boolean forwardParams)
    • getName

      public String getName()
    • withName

      public RestClient withName(String name)
    • isUseCompression

      public boolean isUseCompression()
    • withUseCompression

      public RestClient withUseCompression(boolean useCompression)
    • getCompressionMinSize

      public int getCompressionMinSize()
    • withCompressionMinSize

      public RestClient withCompressionMinSize(int compressionMinSize)
    • getRetryMax

      public int getRetryMax()
    • withRetryMax

      public RestClient withRetryMax(int retryMax)
    • getSocketTimeout

      public int getSocketTimeout()
    • withSocketTimeout

      public RestClient withSocketTimeout(int socketTimeout)
    • getConnectTimeout

      public int getConnectTimeout()
    • withConnectTimeout

      public RestClient withConnectTimeout(int connectTimeout)
    • getRequestTimeout

      public int getRequestTimeout()
    • withRequestTimeout

      public RestClient withRequestTimeout(int requestTimeout)
    • withHttpClient

      public RestClient withHttpClient(org.apache.http.client.HttpClient httpClient)
    • getHttpClient

      protected org.apache.http.client.HttpClient getHttpClient()
    • getExecutor

      public RestClient.Executor getExecutor()
      Returns:
      lazy constructs executor if necessary.
    • withExecutor

      public RestClient withExecutor(RestClient.Executor executor)
    • buildExecutor

      protected RestClient.Executor buildExecutor()
      Build an executor if one was not wired in.

      You can dependency inject your Executor or override this method to provide advanced customizations.

      As a convenience RestClient.threadsMax is configured on the default executor.

      Returns:
      a default new Executor.
    • isForwardHeaders

      public boolean isForwardHeaders()
    • shouldForwardHeader

      protected boolean shouldForwardHeader(String headerKey)
    • withForwardHeaders

      public RestClient withForwardHeaders(boolean forwardHeaders)
    • getIncludeForwardHeaders

      public Set<String> getIncludeForwardHeaders()
    • withIncludeForwardHeaders

      public RestClient withIncludeForwardHeaders(String... headerKeys)
    • withWhitelistedHeaders

      public RestClient withWhitelistedHeaders(String... headerKeys)
      Deprecated.
    • removeIncludeForwardHeader

      public RestClient removeIncludeForwardHeader(String headerKey)
    • getExcludeForwardHeaders

      public Set getExcludeForwardHeaders()
    • withExcludeForwardHeaders

      public RestClient withExcludeForwardHeaders(String... headerKeys)
    • removeExcludeForwardHeader

      public RestClient removeExcludeForwardHeader(String headerKey)
    • isForwardParams

      public boolean isForwardParams()
    • shouldForwardParam

      protected boolean shouldForwardParam(String param)
    • withForwardParams

      public RestClient withForwardParams(boolean forwardParams)
    • getIncludeParams

      public Set getIncludeParams()
    • withIncludeParams

      public RestClient withIncludeParams(String... paramNames)
    • removeIncludeParam

      public RestClient removeIncludeParam(String param)
    • getExcludeParams

      public Set getExcludeParams()
    • withExcludeParams

      public RestClient withExcludeParams(String... paramNames)
    • removeExcludeParam

      public RestClient removeExcludeParam(String param)
    • getRetryTimeoutMin

      public int getRetryTimeoutMin()
    • withRetryTimeoutMin

      public RestClient withRetryTimeoutMin(int retryTimeoutMin)
    • getRetryTimeoutMax

      public int getRetryTimeoutMax()
    • getRetryTimeoutMax

      public RestClient getRetryTimeoutMax(int retryTimeoutMax)
    • getThreadsMax

      public int getThreadsMax()
    • withThreadsMax

      public RestClient withThreadsMax(int threadsMax)