Class ApiClient

java.lang.Object
io.inversion.client.ApiClient

public class ApiClient extends Object
An HttpClient wrapper designed specifically to run inside of an Inversion Request Chain with some extra superpowers.

ApiClient gives you easy or built in:

  • request response listeners that operate on all requests/responses. See ApiClient.withRequestListener()/.withResponseListener()
  • fluent asynchronous response handler api on FutureResponse for response specific handling. See FutureResponse.onResponse()/onSuccess()/onFailure()
  • header forwarding w/ whitelists and blacklists
  • url query string param forwarding w/ whitelist and blacklists
  • lazy runtime host url construction through lookup of "{ApiClient.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).
  • change any request/response in an always thread safe way by overriding doRequest(Request)

Intercepting and transforming requests and responses examples:


      ApiClient client = new ApiClient().withRequestListener(req -> return new Response())//-- edit the request or return your own response to short circuits the remote call
                                          .withResponseListener(res -> res.setStatus(200))//-- edit anything you want about the response

      //-- you can also override "doRequest" to control everything before and after the actual HttpClient call.
      client = new ApiClient("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.doRequest(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 JSMap("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

    • forcedHeaders

      protected final io.inversion.utils.ListMap<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 simply appending to the value list.

      This list is initially empty.

    • requestListeners

      protected final List<ApiClient.RequestListener> requestListeners
    • responseListeners

      protected final List<Consumer<io.inversion.Response>> responseListeners
    • name

      protected String name
      The ApiClient name that will be used for property decoding.
      See Also:
      • Context
    • 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. Any {paramName} variables will be replaced with with values from the current Request Url.
    • 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.

    • includeForwardHeaders

      protected final Set includeForwardHeaders
      Forward these headers when forwardHeaders is true.
      See Also:
    • excludeForwardHeaders

      protected final Set excludeForwardHeaders
      Never forward these headers.
      See Also:
    • 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 excludeParams.

      Default value is false.

    • includeParams

      protected final Set<String> includeParams
      Forward these params when forwardParams is true.
      See Also:
    • excludeParams

      protected final Set<String> excludeParams
      Never forward these params. Contains ["explain"] by default.
      See Also:
    • 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.

    • maxMemoryBuffer

      protected long maxMemoryBuffer
      Responses over this size will be written to a temp file that will be deleted when the Response inputStream is closed (or Response is finalized which closes the stream)
    • executor

      protected ApiClient.Executor executor
      The thread pool executor used to make asynchronous requests. The Executor will expand to threadsMax worker threads.
    • 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 0.

    • socketTimeout

      protected int socketTimeout
      Parameter for default HttpClient configuration

      Default value is 30000ms

      See Also:
      • RequestConfig.Builder.setSocketTimeout(int)
    • connectTimeout

      protected int connectTimeout
      Parameter for default HttpClient configuration

      Default value is 30000ms

      See Also:
      • RequestConfig.Builder.setConnectTimeout(int)
    • connectionRequestTimeout

      protected int connectionRequestTimeout
      Parameter for default HttpClient configuration

      Default value is 30000ms

      See Also:
      • RequestConfig.Builder.setConnectionRequestTimeout(int)
    • maxConPerRoute

      public int maxConPerRoute
      Parameter for default HttpClient configuration

      Default value is 10

      See Also:
      • HttpClientBuilder.setMaxConnPerRoute(int)
    • maxConTotal

      public int maxConTotal
      Parameter for default HttpClient configuration

      Default value is 50ms

      See Also:
      • HttpClientBuilder.setMaxConnTotal(int)
    • evictExpiredConnections

      public boolean evictExpiredConnections
      Parameter for default HttpClient configuration
      See Also:
      • HttpClientBuilder.evictExpiredConnections()
    • evictIdleConnectionsAfterTimeMillis

      public int evictIdleConnectionsAfterTimeMillis
      Parameter for default HttpClient configuration
      See Also:
      • HttpClientBuilder.evictIdleConnections(long, TimeUnit)
    • httpClientBuilder

      protected org.apache.http.impl.client.HttpClientBuilder httpClientBuilder
    • httpClient

      protected org.apache.http.client.HttpClient httpClient
  • Constructor Details

    • ApiClient

      public ApiClient()
    • ApiClient

      public ApiClient(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 ApiClient.FutureResponse get(String fullUrlOrRelativePath)
      Convenience overloading of call(String, String, Map, Object, ListMap) 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 ApiClient.FutureResponse get(String fullUrlOrRelativePath, String queryString)
      Convenience overloading of call(String, String, Map, Object, ListMap) 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 ApiClient.FutureResponse get(String fullUrlOrRelativePath, Map<String,String> params)
      Convenience overloading of call(String, String, Map, Object, ListMap) 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 ApiClient.FutureResponse get(String fullUrlOrRelativePath, String... queryStringNameValuePairs)
      Convenience overloading of call(String, String, Map, Object, ListMap) 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 ApiClient.FutureResponse post(String fullUrlOrRelativePath, Object body)
      Convenience overloading of call(String, String, Map, Object, ListMap) 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 ApiClient.FutureResponse put(String fullUrlOrRelativePath, Object body)
      Convenience overloading of call(String, String, Map, Object, ListMap) 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 ApiClient.FutureResponse patch(String fullUrlOrRelativePath, Object body)
      Convenience overloading of call(String, String, Map, Object, ListMap) 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 ApiClient.FutureResponse delete(String fullUrlOrRelativePath)
      Convenience overloading of call(String, String, Map, Object, ListMap) 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 ApiClient.FutureResponse call(String method, String fullUrlOrRelativePath, Map<String,String> params, Object body, io.inversion.utils.ListMap<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
      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 ApiClient.FutureResponse call(io.inversion.Request request)
      Executes the Request as provided without modification ignoring forwardHeaders/forwardParams etc.

      All of the other 'get/post/put/patch/delete/call' methods will use buildRequest() to construct a Request based on the configured properties of this ApiClient 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 io.inversion.Request buildRequest(String method, String fullUrlOrRelativePath, Map<String,String> params, Object body, io.inversion.utils.ListMap<String,String> headers)
      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.first() root caller 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
      Returns:
      the configure request
    • doRequest

      protected io.inversion.Response doRequest(io.inversion.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 ApiClient 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 ApiClient client = new ApiClient("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.doRequest(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 ApiClient onRequest(ApiClient.RequestListener requestListener)
      Requests listeners can modify the Request. If they return null, request processing/execution will continue. If they return a Response, no additional RequestListeners will be notified and the supplied Response will be used instead of actually making the remote response. In this case all response listeners on this class or the FutureResponse will still be notified.
      Parameters:
      requestListener -
      Returns:
    • onResponse

      public ApiClient onResponse(Consumer<io.inversion.Response> responseListener)
    • replaceVars

      public String replaceVars(io.inversion.Request parentRequest, String url)
      Replaces path parameters with their corresponding request params
    • withUrl

      public ApiClient withUrl(String url)
    • getForcedHeaders

      public io.inversion.utils.ListMap<String,String> getForcedHeaders()
    • withForcedHeader

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

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

      public ApiClient withForwardedHeaders(boolean forwardHeaders)
    • withForwardedParams

      public ApiClient withForwardedParams(boolean forwardParams)
    • getName

      public String getName()
    • withName

      public ApiClient withName(String name)
    • isUseCompression

      public boolean isUseCompression()
    • withUseCompression

      public ApiClient withUseCompression(boolean useCompression)
    • getCompressionMinSize

      public int getCompressionMinSize()
    • withCompressionMinSize

      public ApiClient withCompressionMinSize(int compressionMinSize)
    • withHttpClient

      public ApiClient withHttpClient(org.apache.http.client.HttpClient httpClient)
    • getSocketTimeout

      public int getSocketTimeout()
    • withSocketTimeout

      public ApiClient withSocketTimeout(int socketTimeout)
    • getConnectTimeout

      public int getConnectTimeout()
    • withConnectTimeout

      public ApiClient withConnectTimeout(int connectTimeout)
    • getConnectionRequestTimeout

      public int getConnectionRequestTimeout()
    • withConnectionRequestTimeout

      public ApiClient withConnectionRequestTimeout(int connectionRequestTimeout)
    • getMaxConPerRoute

      public int getMaxConPerRoute()
    • withMaxConPerRoute

      public ApiClient withMaxConPerRoute(int maxConPerRoute)
    • getMaxConTotal

      public int getMaxConTotal()
    • withMaxConTotal

      public ApiClient withMaxConTotal(int maxConTotal)
    • isEvictExpiredConnections

      public boolean isEvictExpiredConnections()
    • withEvictExpiredConnections

      public ApiClient withEvictExpiredConnections(boolean evictExpiredConnections)
    • getEvictIdleConnectionsAfterTimeMillis

      public int getEvictIdleConnectionsAfterTimeMillis()
    • withEvictIdleConnectionsAfterTimeMillis

      public ApiClient withEvictIdleConnectionsAfterTimeMillis(int evictIdleConnectionsAfterTimeMillis)
    • getHttpClient

      public org.apache.http.client.HttpClient getHttpClient()
    • buildHttpClient

      protected org.apache.http.client.HttpClient buildHttpClient(org.apache.http.impl.client.HttpClientBuilder builder) throws Exception
      Throws:
      Exception
    • withHttpClientBuilder

      public ApiClient withHttpClientBuilder(org.apache.http.impl.client.HttpClientBuilder httpClientBuilder)
    • getHttpClientBuilder

      public org.apache.http.impl.client.HttpClientBuilder getHttpClientBuilder()
    • buildDefaultHttpClientBuilder

      public org.apache.http.impl.client.HttpClientBuilder buildDefaultHttpClientBuilder()
    • withExecutor

      public ApiClient withExecutor(ApiClient.Executor executor)
    • getExecutor

      public ApiClient.Executor getExecutor()
      Returns:
      lazy constructs executor if necessary.
    • buildExecutor

      protected ApiClient.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 ApiClient.threadsMax is configured on the default executor.

      Returns:
      a default new Executor.
    • isForwardHeaders

      public boolean isForwardHeaders()
    • shouldForwardHeader

      protected boolean shouldForwardHeader(String headerKey)
    • withForwardHeaders

      public ApiClient withForwardHeaders(boolean forwardHeaders)
    • getIncludeForwardHeaders

      public Set<String> getIncludeForwardHeaders()
    • withIncludeForwardHeaders

      public ApiClient withIncludeForwardHeaders(String... headerKeys)
    • removeIncludeForwardHeader

      public ApiClient removeIncludeForwardHeader(String headerKey)
    • getExcludeForwardHeaders

      public Set getExcludeForwardHeaders()
    • withExcludeForwardHeaders

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

      public ApiClient removeExcludeForwardHeader(String headerKey)
    • isForwardParams

      public boolean isForwardParams()
    • shouldForwardParam

      protected boolean shouldForwardParam(String param)
    • withForwardParams

      public ApiClient withForwardParams(boolean forwardParams)
    • getIncludeParams

      public Set getIncludeParams()
    • withIncludeParams

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

      public ApiClient removeIncludeParam(String param)
    • getExcludeParams

      public Set getExcludeParams()
    • withExcludeParams

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

      public ApiClient removeExcludeParam(String param)
    • getMaxMemoryBuffer

      public long getMaxMemoryBuffer()
    • withMaxMemoryBuffer

      public ApiClient withMaxMemoryBuffer(long maxMemoryBuffer)
    • getThreadsMax

      public int getThreadsMax()
    • withThreadsMax

      public ApiClient withThreadsMax(int threadsMax)