Skip to content

Latest commit

 

History

History
108 lines (87 loc) · 3.66 KB

File metadata and controls

108 lines (87 loc) · 3.66 KB

Advanced Configuration

Logging

Configure the internal logger and verbosity.

HttpClient client = HttpClient.builder()
    .logger(new MyLogger()) 
    .logLevel(LoggerLevel.HEADERS)
    .build();

Reactive Auth & Retries

Implement AuthChallengeHandler to handle 401 Unauthorized responses. The client will retry the request exactly once if the handler returns true.

HttpClient client = HttpClient.builder()
    .authChallengeHandler((clientInstance, response) -> {
        // Refresh token logic here
        tokenService.refreshToken();
        return true; // Retry request
    })
    .build();

Lazy Dynamic Headers

Using a Supplier<String> for headers ensures they are evaluated at the exact moment the request is sent. If an AuthChallengeHandler triggers a retry, the supplier is called again, picking up any updated values (like a refreshed JWT).

client.get(url)
    .authorization(() -> tokenService.getToken()) // Lazy evaluation
    .execute();

Bidirectional Serialization (SPI)

The SerializerProvider interface handles both directions of JSON mapping:

  1. Request: Pass a POJO to .json(object) to have it automatically serialized to JSON.
  2. Response: Use .as(Class) to automatically deserialize the JSON response to a Java object.

Register your provider in META-INF/services/j8a.http.spi.SerializerProvider for automatic discovery.

Interceptors

Interceptors allow you to hook into the request/response lifecycle. Common use cases include global headers, caching, or custom logging.

Example: Custom Interceptor

HttpClient client = HttpClient.builder()
    .interceptor(chain -> {
        // Modify request
        RequestSpecification modified = chain.request().toBuilder()
            .header("X-Custom-Global", "Value")
            .build();
            
        // Proceed down the chain
        Response response = chain.proceed(modified);
        
        // Inspect response
        System.out.println("Status: " + response.getStatusCode());
        
        return response;
    })
    .build();

PATCH Method Support

Standard Java 8 HttpURLConnection does not support PATCH. This library implements a reflection-based workaround to enable it. Note: On Java 9+, you must add --add-opens java.base/java.net=ALL-UNNAMED to your JVM arguments to allow this reflection.

AbstractApiClient (API Wrappers)

Use this base class to create specialized clients for your services. It handles base URLs, default headers, and centralized error handling.

Example: Custom Service Client

This example shows a wrapper that adds a custom API key header to every request and maps 404 errors to a specific exception.

public class UserServiceClient extends AbstractApiClient {

    public UserServiceClient(HttpClient httpClient) {
        super(httpClient, "https://api.myapp.com/v1");
    }

    @Override
    protected Map<String, List<String>> defaultHeaders() {
        return new HeadersBuilder()
                .set("X-API-Key", "secret-key-123")
                .set("Accept", "application/json")
                .build();
    }

    @Override
    protected void handleError(Response response) {
        if (response.getStatusCode() == 404) {
            throw new UserNotFoundException("User not found in MyApp");
        }
        if (response.isError()) {
            throw new RuntimeException("API Error: " + response.getStatusCode());
        }
    }

    public User getUser(String id) {
        // Automatically uses baseUrl and injects default headers
        return get("/users/" + id).as(User.class);
    }

    public void saveUser(User user) {
        post("/users", user).execute();
    }
}