Class RestClient


public class RestClient extends TestClient<RestClient>
REST client for test stubbed rest (StubRest).

client() provides a raw client, configured with: - Random port - Requests logging (@StubRest(logRequests = true), enabled by default) - Enabled restricted headers and method workaround (for url connection, used by in-memory test container) - Set default timeouts to avoid infinite calls - Enabled multipart support (if available in classpath)

Provides the same abilities as a client from ClientSupport.

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

By default, defaults are reset after each test. So defaults could be specified in the test setup method (to apply the same for all tests in class) or just before method call (in method test directly). Automatic rest could be disabled with @StubRest(autoReset = false).

Since:
20.02.2025
  • Constructor Details

    • RestClient

      public RestClient(GuiceyJerseyTest jerseyTest)
      Create a client.
      Parameters:
      jerseyTest - jersey test instance
  • Method Details

    • client

      public jakarta.ws.rs.client.Client client()
      Returns the pre-configured Client for this test.
      Returns:
      the JerseyTest configured Client
    • getRoot

      protected jakarta.ws.rs.client.WebTarget getRoot()
      Description copied from class: TestClient
      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).
      Overrides:
      getRoot in class TestClient<RestClient>
      Returns:
      root target