Class ApiClient


  • public class ApiClient
    extends java.lang.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 Detail

      • forcedHeaders

        protected final io.inversion.utils.ListMap<java.lang.String,​java.lang.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.

      • responseListeners

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

        protected java.lang.String name
        The ApiClient name that will be used for property decoding.
        See Also:
        Context
      • url

        protected java.lang.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.

      • excludeForwardHeaders

        protected final java.util.Set excludeForwardHeaders
        Never forward these headers.
        See Also:
        shouldForwardHeader(String)
      • 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 java.util.Set<java.lang.String> includeParams
        Forward these params when forwardParams is true.
        See Also:
        shouldForwardParam(String)
      • excludeParams

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

      • ApiClient

        public ApiClient()
      • ApiClient

        public ApiClient​(java.lang.String name)
        Parameters:
        name - the prefix used to look up property values from the environment if they have not already been wired
    • Method Detail

      • get

        public ApiClient.FutureResponse get​(java.lang.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​(java.lang.String fullUrlOrRelativePath,
                                            java.lang.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​(java.lang.String fullUrlOrRelativePath,
                                            java.util.Map<java.lang.String,​java.lang.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​(java.lang.String fullUrlOrRelativePath,
                                            java.lang.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​(java.lang.String fullUrlOrRelativePath,
                                             java.lang.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​(java.lang.String fullUrlOrRelativePath,
                                            java.lang.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​(java.lang.String fullUrlOrRelativePath,
                                              java.lang.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​(java.lang.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​(java.lang.String method,
                                             java.lang.String fullUrlOrRelativePath,
                                             java.util.Map<java.lang.String,​java.lang.String> params,
                                             java.lang.Object body,
                                             io.inversion.utils.ListMap<java.lang.String,​java.lang.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​(java.lang.String method,
                                                 java.lang.String fullUrlOrRelativePath,
                                                 java.util.Map<java.lang.String,​java.lang.String> params,
                                                 java.lang.Object body,
                                                 io.inversion.utils.ListMap<java.lang.String,​java.lang.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​(java.util.function.Consumer<io.inversion.Response> responseListener)
      • replaceVars

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

        public ApiClient withUrl​(java.lang.String url)
      • getForcedHeaders

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

        public ApiClient withForcedHeader​(java.lang.String name,
                                          java.lang.String value)
      • withForcedHeaders

        public ApiClient withForcedHeaders​(java.lang.String... headers)
      • withForwardedHeaders

        public ApiClient withForwardedHeaders​(boolean forwardHeaders)
      • withForwardedParams

        public ApiClient withForwardedParams​(boolean forwardParams)
      • getName

        public java.lang.String getName()
      • withName

        public ApiClient withName​(java.lang.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 java.lang.Exception
        Throws:
        java.lang.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()
      • 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​(java.lang.String headerKey)
      • withForwardHeaders

        public ApiClient withForwardHeaders​(boolean forwardHeaders)
      • getIncludeForwardHeaders

        public java.util.Set<java.lang.String> getIncludeForwardHeaders()
      • withIncludeForwardHeaders

        public ApiClient withIncludeForwardHeaders​(java.lang.String... headerKeys)
      • removeIncludeForwardHeader

        public ApiClient removeIncludeForwardHeader​(java.lang.String headerKey)
      • getExcludeForwardHeaders

        public java.util.Set getExcludeForwardHeaders()
      • withExcludeForwardHeaders

        public ApiClient withExcludeForwardHeaders​(java.lang.String... headerKeys)
      • removeExcludeForwardHeader

        public ApiClient removeExcludeForwardHeader​(java.lang.String headerKey)
      • isForwardParams

        public boolean isForwardParams()
      • shouldForwardParam

        protected boolean shouldForwardParam​(java.lang.String param)
      • withForwardParams

        public ApiClient withForwardParams​(boolean forwardParams)
      • getIncludeParams

        public java.util.Set getIncludeParams()
      • withIncludeParams

        public ApiClient withIncludeParams​(java.lang.String... paramNames)
      • removeIncludeParam

        public ApiClient removeIncludeParam​(java.lang.String param)
      • getExcludeParams

        public java.util.Set getExcludeParams()
      • withExcludeParams

        public ApiClient withExcludeParams​(java.lang.String... paramNames)
      • removeExcludeParam

        public ApiClient removeExcludeParam​(java.lang.String param)
      • getMaxMemoryBuffer

        public long getMaxMemoryBuffer()
      • withMaxMemoryBuffer

        public ApiClient withMaxMemoryBuffer​(long maxMemoryBuffer)
      • getThreadsMax

        public int getThreadsMax()
      • withThreadsMax

        public ApiClient withThreadsMax​(int threadsMax)