Class TestClient<T extends TestClient<?>>

java.lang.Object
ru.vyarus.dropwizard.guice.test.client.builder.TestClientDefaults<T>
ru.vyarus.dropwizard.guice.test.client.TestClient<T>
Type Parameters:
T - actual client type
Direct Known Subclasses:
ClientSupport, ResourceClient, RestClient

public class TestClient<T extends TestClient<?>> extends TestClientDefaults<T>
Wrapper for JerseyClient. Jersey client is a general-purpose client and this api specialized for tests. Also, the jersey request builder is split into two parts: target and request. This api unifies it into a single step, for simplicity.

The "defaults" concept: some values (query params, headers, cookies, etc.) could be configured once for all client requests (this is usually handy for tests, for example, to unify authorization). See "default*" methods for details (for example, TestClientDefaults.defaultHeader(String, Object)). Defaults could be cleared with TestClientDefaults.reset() or printed into console with TestClientDefaults.printDefaults()

There are multiple ways to perform a request:

All "build*" methods return a custom builder object with all the same configuration options as the original jersey client builder, but all gathered in one place (easier to use). This builder could return either directly mapped object (with TestClientRequestBuilder.as(Class)) or a special response object wrapper with pre-defined assertions to simplify testing (TestClientRequestBuilder.expectSuccess(Integer...) or TestClientRequestBuilder.expectFailure(Integer...) or without response validation TestClientRequestBuilder.invoke()).

All methods support (optional) string format for a path. For example, the call client.get("/entity/%s", Entity.class, 12) will use "/entity/12/" as target path.

Examples:


     TestClient client;

     // jersey api (no defaults applied)
     Entity res = client.target("/some/path").request().get(Entity.class);

     // jersey api (with defaults applied)
     Entity res = client.request("/some/path").get(Entity.class);

     // shortcut method
     Entity res = client.get("/some/path", Entity.class);

     // shortcut with composite entity type (note diamond operator usage):
     List<Entity> res = client.get("/some/path", new GenericType<>() {});

     // builder method
     Entity res = client.buildGet("/some/path")
              .header("Something", "Value")
              .invoke(Entity.class);

     // builder with response assertions ():
     Entity res = client.buildGet("/some/path")
              // error thrown if response is not success with (optional) exact status validation
              .expectSuccess(200)
              // assertion error if value will not match or cookie absent
              .assertCookie("Name", "Value")
              // assertion error if value will not match or header absent
              .assertHeader("Something", "Value")
              // map entity
              .as(EntityClass)

     // defaults demo:
     client.defaultHeader("Authorization", "Bearer 1234567890");

     // request would contain the default header
     Entity res = client.get("/some/path", Entity.class);
 

The main idea behind chained assertions is redundant variables avoidance in test.

Note that builder method return AutoCloseable object (same as Response) because a response object must be closed (response is closed when response body is consumed). Because of this your IDE could warn you that the result of, for example, TestClientRequestBuilder.invoke() must be used with "try-with-resources" statement. In most cases, you can ignore this warning as guicey tracks all such wrapped responses and would close it after a test application shutdown.

Builder api does not hide jersey api: if required, you can modify target directly with TestClientDefaults.defaultPathConfiguration(java.util.function.Function) or jersey builder with TestClientDefaults.defaultRequestConfiguration(java.util.function.Consumer).

Builder supports jersey client properties (TestClientDefaults.defaultProperty(String, Object)) and extensions TestClientDefaults.defaultRegister(Class) and TestClientDefaults.defaultRegister(Object). As an example, property could be used to disable redirects (TestClientRequestBuilder.notFollowRedirects() which is used automatically by TestClientRequestBuilder.expectRedirect(Integer...)). For a custom extension example see TestClientRequestBuilder.noBodyMappingForVoid() (which is used automatically by TestClientRequestBuilder.asVoid() to ignore response body mapping for void requests).

The client could be used to build sub-clients. In this case all defaults will be inherited from the parent client. For example, we have a general rest client, but our particular test would check only one resource. In this case we can create a sub-client for the resource path to avoid it in all method calls:


     TestClient api;
     TestClient subRest = api.subClient("/resource/{param}/path")
              .defaultPathParam("param", 123);
      // this would call "/resource/123/path/method"
     Entity res = subRest.get("/method", Entity.class);
 

TestClient is a general client class, but there are special client classes for rest (extending it): ResourceClient (could be obtained from the root) and object (which is also a test client))

Since:
13.09.2025
  • Constructor Details

    • TestClient

      public TestClient(@Nullable TestRequestConfig defaults)
      Construct a client without a base root path and defaults. This constructor could be used ONLY by extending classes, which override getRoot() (these are root classes providing initial integration with test or stub clients (ClientSupport and RestClient) because it is not possible to provide root target in constructor)
      Parameters:
      defaults - default configurations
    • TestClient

      public TestClient(@Nullable Supplier<jakarta.ws.rs.client.WebTarget> root, @Nullable TestRequestConfig defaults)
      Construct a jersey client wrapper.
      Parameters:
      root - root target supplier
      defaults - (optional) defaults
  • Method Details

    • getBaseUri

      public URI getBaseUri()
      Returns:
      base URI for this client
    • target

      public jakarta.ws.rs.client.WebTarget target(String path, Object... args)
      Creates a web target to call under testing. This is a pure jersey api method for generic cases: in most cases, it would be simplir to use provided shortcuts (like get(String, Object...)).

      Example: .target("/smth/12/other").request().buildGet().invoke() String format: .target("/smth/%s/other", 12).request().buildGet().invoke()

      WARNING: any specified defaults do not affect this method!

      Parameters:
      path - target path, relative to client root (could contain String.format() placeholders: %s)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      jersey web target object
    • request

      public jakarta.ws.rs.client.Invocation.Builder request(String path, Object... args)
      Create request for provided target with all defaults applied. Use for generic cases when jersey api usage required. In other cases use provided shortcuts or builder methods.
      Parameters:
      path - target path, relative to client root (could contain String.format() placeholders: %s)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      request object, ready to be sent
    • subClient

      public TestClient<?> subClient(String path, Object... args)
      Construct a sub-client with the provided path. Useful when performing multiple tests for common base url (e.g. testing one resource methods).
      
          TestClient api;
          TestClient subRest = api.subClient("/resource/{param}/path")
                   .defaultPathParam("param", 123);
          // this would call "/resource/123/path/method"
          Entity res = subRest.get("/method", Entity.class);
       

      All defaults, configured for the current client, will be inherited in a sub-client. If this is not required, just clean defaults after creation: client.subClient("path").reset().

      Parameters:
      path - target client root path (could contain String.format() placeholders: %s)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      new client with a different root path
    • subClient

      public TestClient<?> subClient(Consumer<jakarta.ws.rs.core.UriBuilder> consumer)
      Create a new sub-client for a specified path. Sub path is constructed using jersey builder. For example: client.subClient(builder -> builder.path("path").path("sub")).

      This might be useful for constructing complex paths with matrix parameters inside. Note that the target client could be easily "typed" with asRestClient(Class) method. Or use subClient(String, Object...).

      All defaults, configured for the current client, will be inherited in a sub-client. If this is not required, just clean defaults after creation: client.subClient(...).reset().

      Parameters:
      consumer - uri builder configurator
      Returns:
      client with a constructed path (relative to the current client path)
    • subClient

      public <K> ResourceClient<K> subClient(Consumer<jakarta.ws.rs.core.UriBuilder> consumer, Class<K> resource)
      Create a new rest client with a custom path.
      Type Parameters:
      K - resource type
      Parameters:
      consumer - path builder
      resource - resource type
      Returns:
      rest client for provided resource
    • restClient

      public <R> ResourceClient<R> restClient(Class<R> resource)
      Create a new sub-client for a specified resource class (appends a resource path, obtained from Path annotation, to the current client path). Method is useful when generic rest path must be "typed" with a resource type (to be able to call resource methods directly).

      In case of sub-resources, use subResourceClient(String, Class, Object...) to properly specify sub-resource mapping path (from lookup method): ResourceClient rest = client.subResourceClient("path", SubResource.class). IMPORTANT: this is NOT THE SAME: client.subClient("path").restClient(SubResource.class) because "restClient()" call would append path from resource, which is ignored for sub resources!.

      Defaults could be used to declare path parameter values: ResourceClient rest = client.restClient(Resource.class).defaultPathParam("param", "value") where a resource class path is like "/some/{param}/path". With the default path param, there would be no need to declare it for each request call.

      All defaults, configured for the current client, will be inherited in a sub-client. If this is not required, just clean defaults after creation: client.subClient(ResClass.class).reset().

      Type Parameters:
      R - resource type
      Parameters:
      resource - resource class one to build a path for
      Returns:
      resource client (with a resource path, relative to the current client path)
    • subResourceClient

      public <R> ResourceClient<R> subResourceClient(String path, Class<R> subResource, Object... args)
      Create a sub client for the sub-resource.

      IMPORTANT: Path, declared on sub-resource class is ignored! Only lookup method path is counted. For example, @Path("/sub") SubResource something() {...} means all sub resource methods would be available on "/sub/*".

      Type Parameters:
      R - sub-resource type
      Parameters:
      path - sub-resource mapping path (from sub-resource method; could contain String.format() placeholders: %s)
      args - variables for path placeholders (String.format() arguments)
      subResource - sub-resource
      Returns:
      sub-resource client
    • asRestClient

      public <R> ResourceClient<R> asRestClient(Class<R> resource)
      Cast current path as provided resource (full!) path. Use-case: resources were mapped on non-standard path (admin context resources or internal resource mappings).

      IMPORTANT: this call will ignore resource @Path annotation - it assumes that the current path is already a resource path.

      Type Parameters:
      R - resource type
      Parameters:
      resource - resource type
      Returns:
      rest client for provided resource
    • get

      public void get(String path, Object... args)
      GET call shortcut. Almost the same as jersey client.target(path).request().get(Void.class):

      To send a form (urlencoded) use buildForm(String, Object...): buildForm("/path/%s/sub", 12).param("A", 1)..buildGet().invoke(Some.class).

      Additional headers, query params, etc. could be provided with defaults (e.g. TestClientDefaults.defaultHeader(String, Object)). For additional request-specific configuration use buildGet(String, Object...).

      String format could be used for path formatting: client.get("/smth/%s/other", 12)

      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      args - variables for path placeholders (String.format() arguments)
    • get

      public <R> R get(String path, @Nullable Class<R> result, Object... args)
      GET call shortcut. Almost the same as jersey client.target(path).request().get(Some.class):

      To send a form (urlencoded) use buildForm(String, Object...): buildForm("/path/%s/sub", 12).param("A", 1)..buildGet().invoke(Some.class).

      • Exception thrown if the result is not successful (not 2xx)
      • For StubRest resource exception propagated if no exception mappers registered

      Additional headers, query params, etc. could be provided with defaults (e.g. TestClientDefaults.defaultHeader(String, Object)). For additional request-specific configuration use buildGet(String, Object...).

      String format could be used for path formatting: Some res = client.get("/smth/%s/other", Some.class, 12)

      Type Parameters:
      R - result type
      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      result - result type (null or Void to ignore response body)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      mapped result object or null (if class not declared)
    • get

      public <R> R get(String path, @Nullable jakarta.ws.rs.core.GenericType<R> result, Object... args)
      GET call shortcut. Almost the same as jersey client.target(path).request().get(new GenericType<List<Some>>(){}):

      To send a form (urlencoded) use buildForm(String, Object...): buildForm("/path/%s/sub", 12).param("A", 1)..buildGet().invoke(Some.class).

      • Exception thrown if the result is not successful (not 2xx)
      • For StubRest resource exception propagated if no exception mappers registered

      Additional headers, query params, etc. could be provided with defaults (e.g. TestClientDefaults.defaultHeader(String, Object)). For additional request-specific configuration use buildGet(String, Object...).

      String format could be used for path formatting: List<Some> res = client.get("/smth/%s/other", new GenericType<>() {}, 12)

      Type Parameters:
      R - result type
      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      result - result type (null or Void to ignore response body)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      mapped result object or null (if class not declared)
    • post

      public void post(String path, @Nullable Object body, Object... args)
      POST call shortcut. Almost the same as jersey client.target(path).request().post(entity, Void.class)):

      If body is already an Entity - it will be used as is, other objects would be converted to json entity (Entity.json(Object)).

      For forms (urlencoded and multipart) use buildForm(String, Object...): buildForm("/path/%s/sub", 12).buildPost().invoke(Some.class).

      Additional headers, query params, etc. could be provided with defaults (e.g. TestClientDefaults.defaultHeader(String, Object)). For additional request-specific configuration use buildPost(String, Object, Object...).

      String format could be used for path formatting: client.post("/smth/%s/other", object, 12)

      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      body - entity object (everything except Entity converted to JSON)
      args - variables for path placeholders (String.format() arguments)
    • post

      public <R> R post(String path, @Nullable Object body, @Nullable Class<R> result, Object... args)
      POST call shortcut. Almost the same as jersey client.target(path).request().post(entity, Some.class)):

      If body is already an Entity - it will be used as is, other objects would be converted to json entity (Entity.json(Object)).

      For forms (urlencoded and multipart) use buildForm(String, Object...): buildForm("/path/%s/sub", 12).param("A", 1)..buildPost().invoke(Some.class).

      • Exception thrown if the result is not successful (not 2xx)
      • For StubRest resource exception propagated if no exception mappers registered

      Additional headers, query params, etc. could be provided with defaults (e.g. TestClientDefaults.defaultHeader(String, Object)). For additional request-specific configuration use buildPost(String, Object, Object...).

      String format could be used for path formatting: Some res = client.post("/smth/%s/other", object, Some.class, 12)

      Type Parameters:
      R - result type
      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      body - entity object (everything except Entity converted to JSON)
      result - result type (null or Void to ignore response body)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      mapped result object or null (if class not declared)
    • post

      public <R> R post(String path, @Nullable Object body, @Nullable jakarta.ws.rs.core.GenericType<R> result, Object... args)
      POST call shortcut. Almost the same as jersey client.target(path).request().post(entity, new GenericType<List<Some>>(){})):

      If body is already an Entity - it will be used as is, other objects would be converted to json entity (Entity.json(Object)).

      For forms (urlencoded and multipart) use buildForm(String, Object...): buildForm("/path/%s/sub", 12).param("A", 1)..buildPost().invoke(Some.class).

      • Exception thrown if the result is not successful (not 2xx)
      • For StubRest resource exception propagated if no exception mappers registered

      Additional headers, query params, etc. could be provided with defaults (e.g. TestClientDefaults.defaultHeader(String, Object)). For additional request-specific configuration use buildPost(String, Object, Object...).

      String format could be used for path formatting: List<Some> res = client.post("/smth/%s/other", object, new GenericType<>(){}, 12)

      Type Parameters:
      R - result type
      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      body - entity object (everything except Entity converted to JSON)
      result - result type (null or Void to ignore response body)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      mapped result object or null (if class not declared)
    • put

      public void put(String path, Object body, Object... args)
      PUT call shortcut. Almost the same as jersey client.target(path).request().put(entity, Void.class)):

      If body is already an Entity - it will be used as is, other objects would be converted to json entity (Entity.json(Object)).

      Additional headers, query params, etc. could be provided with defaults (e.g. TestClientDefaults.defaultHeader(String, Object)). For additional request-specific configuration use buildPut(String, Object, Object...).

      String format could be used for path formatting: client.put("/smth/%s/other", object, 12)

      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      body - entity object (everything except Entity converted to JSON)
      args - variables for path placeholders (String.format() arguments)
    • put

      public <R> R put(String path, Object body, @Nullable Class<R> result, Object... args)
      PUT call shortcut. Almost the same as jersey client.target(path).request().put(entity, Some.class)):

      If body is already an Entity - it will be used as is, other objects would be converted to json entity (Entity.json(Object)).

      • Exception thrown if the result is not successful (not 2xx)
      • For StubRest resource exception propagated if no exception mappers registered

      Additional headers, query params, etc. could be provided with defaults (e.g. TestClientDefaults.defaultHeader(String, Object)). For additional request-specific configuration use buildPut(String, Object, Object...).

      String format could be used for path formatting: Some res = client.put("/smth/%s/other", object, Some.class, 12)

      Type Parameters:
      R - result type
      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      body - entity object (everything except Entity converted to JSON)
      result - result type (null or Void to ignore response body)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      mapped result object or null (if class not declared)
    • put

      public <R> R put(String path, Object body, @Nullable jakarta.ws.rs.core.GenericType<R> result, Object... args)
      PUT call shortcut. Almost the same as jersey client.target(path).request().put(entity, new GenericType<List<Some>>(){})):

      If body is already an Entity - it will be used as is, other objects would be converted to json entity (Entity.json(Object)).

      • Exception thrown if the result is not successful (not 2xx)
      • For StubRest resource exception propagated if no exception mappers registered

      Additional headers, query params, etc. could be provided with defaults (e.g. TestClientDefaults.defaultHeader(String, Object)). For additional request-specific configuration use buildPut(String, Object, Object...).

      String format could be used for path formatting: List<Some> res = client.put("/smth/%s/other", object, new GenericType<>(){}, 12)

      Type Parameters:
      R - result type
      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      body - entity object (everything except Entity converted to JSON)
      result - result type (null or Void to ignore response body)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      mapped result object or null (if class not declared)
    • patch

      public void patch(String path, @Nullable Object body, Object... args)
      PATCH call shortcut. Almost the same as jersey client.target(path).request().build("PATCH").invoke(Void.class)):

      If body is already an Entity - it will be used as is, other objects would be converted to json entity (Entity.json(Object)).

      WARNING: in integration tests (real http call, not stub) the jersey client would use HttpUrlConnectorProvider which have problems with PATCH calls on JDK > 16 (requires additional --add-opens). To workaround this Apache5ConnectorProvider could be used. Guicey provides custom ApacheTestClientFactory for using apache client, which could be enabled with shortcut in test extensions (for example, TestDropwizardApp.apacheClient()).

      Additional headers, query params, etc. could be provided with defaults (e.g. TestClientDefaults.defaultHeader(String, Object)). For additional request-specific configuration use buildPatch(String, Object, Object...).

      String format could be used for path formatting: client.patch("/smth/%s/other", object, 12)

      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      body - entity object (everything except Entity converted to JSON)
      args - variables for path placeholders (String.format() arguments)
    • patch

      public <R> R patch(String path, @Nullable Object body, @Nullable Class<R> result, Object... args)
      PATCH call shortcut. Almost the same as jersey client.target(path).request().build("PATCH").invoke(Some.class)):

      If body is already an Entity - it will be used as is, other objects would be converted to json entity (Entity.json(Object)).

      WARNING: in integration tests (real http call, not stub) the jersey client would use HttpUrlConnectorProvider which have problems with PATCH calls on JDK > 16 (requires additional --add-opens). To workaround this Apache5ConnectorProvider could be used. Guicey provides custom ApacheTestClientFactory for using apache client, which could be enabled with shortcut in test extensions (for example, TestDropwizardApp.apacheClient()).

      • Exception thrown if the result is not successful (not 2xx)
      • For StubRest resource exception propagated if no exception mappers registered

      Additional headers, query params, etc. could be provided with defaults (e.g. TestClientDefaults.defaultHeader(String, Object)). For additional request-specific configuration use buildPatch(String, Object, Object...).

      String format could be used for path formatting: Some res = client.patch("/smth/%s/other", object, Some.class, 12)

      Type Parameters:
      R - result type
      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      body - entity object (everything except Entity converted to JSON)
      result - result type (null or Void to ignore response body)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      mapped result object or null (if class not declared)
    • patch

      public <R> R patch(String path, @Nullable Object body, @Nullable jakarta.ws.rs.core.GenericType<R> result, Object... args)
      PATCH call shortcut. Almost the same as jersey client.target(path).request().build("PATCH").invoke(new GenericType<List<Some>>(){})):

      If body is already an Entity - it will be used as is, other objects would be converted to json entity (Entity.json(Object)).

      WARNING: in integration tests (real http call, not stub) the jersey client would use HttpUrlConnectorProvider which have problems with PATCH calls on JDK > 16 (requires additional --add-opens). To workaround this Apache5ConnectorProvider could be used. Guicey provides custom ApacheTestClientFactory for using apache client, which could be enabled with shortcut in test extensions (for example, TestDropwizardApp.apacheClient()).

      • Exception thrown if the result is not successful (not 2xx)
      • For StubRest resource exception propagated if no exception mappers registered

      Additional headers, query params, etc. could be provided with defaults (e.g. TestClientDefaults.defaultHeader(String, Object)). For additional request-specific configuration use buildPatch(String, Object, Object...).

      String format could be used for path formatting: List<Some> res = client.patch("/smth/%s/other", object, new GenericType<>(){}, 12)

      Type Parameters:
      R - result type
      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      body - entity object (everything except Entity converted to JSON)
      result - result type (null or Void to ignore response body)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      mapped result object or null (if class not declared)
    • delete

      public void delete(String path, Object... args)
      DELETE call shortcut. Almost the same as jersey client.target(path).request().delete(Void.class):

      According to spec, HTTP DELETE should not support body and so there are no shortcuts with body. If you need to send DELETE with body use general builder: build(HttpMethod.DELETE, "/some/path", object).invoke(Some.class).

      Additional headers, query params, etc. could be provided with defaults (e.g. TestClientDefaults.defaultHeader(String, Object)). For additional request-specific configuration use buildDelete(String, Object...).

      String format could be used for path formatting: client.delete("/smth/%s/other", 12)

      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      args - variables for path placeholders (String.format() arguments)
    • delete

      public <R> R delete(String path, @Nullable Class<R> result, Object... args)
      PUT call shortcut. Almost the same as jersey client.target(path).request().put(entity, Some.class)):

      According to spec, HTTP DELETE should not support body and so there are no shortcuts with body. If you need to send DELETE with body use general builder: build(HttpMethod.DELETE, "/some/path", object).invoke(Some.class).

      • Exception thrown if the result is not successful (not 2xx)
      • For StubRest resource exception propagated if no exception mappers registered

      Additional headers, query params, etc. could be provided with defaults (e.g. TestClientDefaults.defaultHeader(String, Object)). For additional request-specific configuration use buildDelete(String, Object...).

      String format could be used for path formatting: Some res = client.delete("/smth/%s/other", Some.class, 12)

      Type Parameters:
      R - result type
      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      result - result type (null or Void to ignore response body)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      mapped result object or null (if class not declared)
    • delete

      public <R> R delete(String path, @Nullable jakarta.ws.rs.core.GenericType<R> result, Object... args)
      DELETE call shortcut. Almost the same as jersey client.target(path).request().delete(entity, new GenericType<List<Some>>(){})):

      According to spec, HTTP DELETE should not support body and so there are no shortcuts with body. If you need to send DELETE with body use general builder: build(HttpMethod.DELETE, "/some/path", object).invoke(Some.class).

      • Exception thrown if the result is not successful (not 2xx)
      • For StubRest resource exception propagated if no exception mappers registered

      Additional headers, query params, etc. could be provided with defaults (e.g. TestClientDefaults.defaultHeader(String, Object)). For additional request-specific configuration use buildDelete(String, Object...).

      String format could be used for path formatting: Some res = client.delete("/smth/%s/other", new GenericType<>(){}, 12)

      Type Parameters:
      R - result type
      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      result - result type (null or Void to ignore response body)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      mapped result object or null (if class not declared)
    • build

      public TestClientRequestBuilder build(String method, String path, @Nullable Object body, Object... args)
      Generic request builder.

      Body is not required. If body is an Entity - it will be used as is, other objects would be converted to json entity (Entity.json(Object)).

      Defaults like TestClientDefaults.defaultHeader(String, Object) are applied.

      Parameters:
      method - http method
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      body - optional request body (everything except Entity converted to JSON)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      request builder
      See Also:
      • HttpMethod
    • buildGet

      public TestClientRequestBuilder buildGet(String path, Object... args)
      GET request builder.

      Example usage: buildGet("/path/%s/sub", 12.header("A", 1).invoke(Some.class)}

      In simple cases use shortcut: get(String, Class, Object...).

      For (urlencoded) forms use buildForm(String, Object...): buildForm("/path/%s/sub", 12).param("A", 1)..buildGet().invoke(Some.class).

      Defaults like TestClientDefaults.defaultHeader(String, Object) are applied.

      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      request builder
    • buildPost

      public TestClientRequestBuilder buildPost(String path, Object entity, Object... args)
      POST request builder.

      Example usage: buildPost("/path/%s/sub", object, 12.header("A", 1).invoke(Some.class)}

      In simple cases use shortcut: post(String, Object, Class, Object...).

      For forms (urlencoded and multipart) use buildForm(String, Object...): buildForm("/path/%s/sub", 12).param("A", 1)..buildPost().invoke(Some.class).

      Defaults like TestClientDefaults.defaultHeader(String, Object) are applied.

      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      entity - request body (everything except Entity converted to JSON)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      request builder
    • buildPut

      public TestClientRequestBuilder buildPut(String path, Object entity, Object... args)
      PUT request builder.

      Example usage: buildPut("/path/%s/sub", object, 12.header("A", 1).invoke(Some.class)}

      In simple cases use shortcut: put(String, Object, Class, Object...).

      Defaults like TestClientDefaults.defaultHeader(String, Object) are applied.

      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      entity - request body (everything except Entity converted to JSON)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      request builder
    • buildPatch

      public TestClientRequestBuilder buildPatch(String path, Object entity, Object... args)
      PATCH request builder.

      Example usage: buildPatch("/path/%s/sub", object, 12.header("A", 1).invoke(Some.class)}

      In simple cases use shortcut: patch(String, Object, Class, Object...).

      Defaults like TestClientDefaults.defaultHeader(String, Object) are applied.

      WARNING: in integration tests (real http call, not stub) the jersey client would use HttpUrlConnectorProvider which have problems with PATCH calls on JDK > 16 (requires additional --add-opens). To workaround this Apache5ConnectorProvider could be used. Guicey provides custom ApacheTestClientFactory for using apache client, which could be enabled with shortcut in test extensions (for example, TestDropwizardApp.apacheClient()).

      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      entity - request body (everything except Entity converted to JSON)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      request builder
    • buildDelete

      public TestClientRequestBuilder buildDelete(String path, Object... args)
      DELETE request builder.

      Example usage: buildDelete("/path/%s/sub", 12.header("A", 1).invoke(Some.class)}

      In simple cases use shortcut: delete(String, Class, Object...).

      Defaults like TestClientDefaults.defaultHeader(String, Object) are applied.

      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      request builder
    • buildForm

      public FormBuilder buildForm(@Nullable String path, Object... args)
      Build urlencoded or multipart form for GET (only urlencoded) and POST.

      Important: multipart support requires an additional dependency: 'org.glassfish.jersey.media:jersey-media-multipart'.

      The type of the form is detected by provided values: if at least one value requires multipart, then a multipart entity is created, otherwise urlencoded entity created. Only urlencoded entity could be used with GET. Multipart form type could be explicitly forced with FormBuilder.forceMultipart().

      Example urlencoded form usage:

      
           buildForm(...)
           .param("name1", value1)
           .param("name2", value2)
           .buildPost()
           .invoke()
       

      Example multipart form usage:

      
           buildForm(...)
           .param("name1", value1)
           .param("file", file)
           .buildPost()
           .invoke()
       

      Also, builder could be used just for entity building: FormBuilder.buildEntity() (for manual entity usage).

      Form build would automatically serialiaze java.util and java.time dates into String. To modify date formats use TestClientDefaults.defaultFormDateFormatter(java.text.DateFormat) and TestClientDefaults.defaultFormDateTimeFormatter(java.time.format.DateTimeFormatter) (or in builder directly: FormBuilder.dateFormatter(java.text.DateFormat), FormBuilder.dateTimeFormatter(java.time.format.DateTimeFormatter)).

      See FormBuilder.param(String, Object) for more details about parameter values conversion.

      Use null path to build entity: buildForm(null).param().buildEntity().

      Parameters:
      path - target path, relative to rest root (could contain String.format() placeholders: %s)
      args - variables for path placeholders (String.format() arguments)
      Returns:
      form builder
    • toString

      public String toString()
      Overrides:
      toString in class Object
    • getEntity

      protected jakarta.ws.rs.client.Entity<?> getEntity(Object entity)
      Check if provided value is already an entity.
      Parameters:
      entity - value to check
      Returns:
      entity itself if value is an entity or json entity
    • getRoot

      protected jakarta.ws.rs.client.WebTarget getRoot()
      Subclasses could override this method: this is required because it is not always possible to provide the correct root target in the constructor (when this method is overridden root, provided in the constructor is null).
      Returns:
      root target