Helidon WebClient is a comprehensive HTTP client library for Java microservices supporting HTTP/1.1, HTTP/2, and protocol negotiation with virtual thread support.
—
Fluent API for building and executing HTTP requests with support for all HTTP methods, headers, query parameters, request bodies, and typed response handling.
Convenient methods for common HTTP operations with optional URI parameters.
/**
* Create a request for a specific HTTP method
* @param method HTTP method
* @return a new request (not thread safe)
*/
REQ method(Method method);
/**
* Shortcut for GET method with URI
* @param uri path to resolve against base URI, or full URI
* @return a new request (not thread safe)
*/
default REQ get(String uri);
/**
* Shortcut for GET method with default path
* @return a new request (not thread safe)
*/
default REQ get();
/**
* Shortcut for POST method with URI
* @param uri path to resolve against base URI, or full URI
* @return a new request (not thread safe)
*/
default REQ post(String uri);
/**
* Shortcut for POST method with default path
* @return a new request (not thread safe)
*/
default REQ post();
/**
* Shortcut for PUT method with URI
* @param uri path to resolve against base URI, or full URI
* @return a new request (not thread safe)
*/
default REQ put(String uri);
/**
* Shortcut for PUT method with default path
* @return a new request (not thread safe)
*/
default REQ put();
/**
* Shortcut for DELETE method with URI
* @param uri path to resolve against base URI, or full URI
* @return a new request (not thread safe)
*/
default REQ delete(String uri);
/**
* Shortcut for DELETE method with default path
* @return a new request (not thread safe)
*/
default REQ delete();
/**
* Shortcut for HEAD method with URI
* @param uri path to resolve against base URI, or full URI
* @return a new request (not thread safe)
*/
default REQ head(String uri);
/**
* Shortcut for HEAD method with default path
* @return a new request (not thread safe)
*/
default REQ head();
/**
* Shortcut for OPTIONS method with URI
* @param uri path to resolve against base URI, or full URI
* @return a new request (not thread safe)
*/
default REQ options(String uri);
/**
* Shortcut for OPTIONS method with default path
* @return a new request (not thread safe)
*/
default REQ options();
/**
* Shortcut for TRACE method with URI
* @param uri path to resolve against base URI, or full URI
* @return a new request (not thread safe)
*/
default REQ trace(String uri);
/**
* Shortcut for TRACE method with default path
* @return a new request (not thread safe)
*/
default REQ trace();
/**
* Shortcut for PATCH method with URI
* @param uri path to resolve against base URI, or full URI
* @return a new request (not thread safe)
*/
default REQ patch(String uri);
/**
* Shortcut for PATCH method with default path
* @return a new request (not thread safe)
*/
default REQ patch();Usage Examples:
import io.helidon.webclient.api.WebClient;
import io.helidon.http.Method;
WebClient client = WebClient.create();
// Using method shortcuts
String getResponse = client.get("/api/users").requestEntity(String.class);
String postResponse = client.post("/api/users").submit(userData, String.class).entity();
// Using generic method
String patchResponse = client.method(Method.PATCH)
.uri("/api/users/123")
.submit(updateData, String.class)
.entity();Configure the target URI for requests with support for path parameters, query parameters, and fragments.
/**
* Configure request URI
* @param uri full URI or path to resolve against base URI
* @return request instance
*/
T uri(String uri);
/**
* Configure request URI
* @param uri java.net.URI instance
* @return request instance
*/
T uri(URI uri);
/**
* Configure request URI
* @param uri ClientUri instance
* @return request instance
*/
T uri(ClientUri uri);
/**
* Configure path component (resolves against base URI)
* @param uri path component
* @return request instance
*/
T path(String uri);
/**
* Replace path parameters in URI template
* @param name parameter name
* @param value parameter value
* @return request instance
*/
T pathParam(String name, String value);
/**
* Add query parameters to the request
* @param name parameter name
* @param values parameter values
* @return request instance
*/
T queryParam(String name, String... values);
/**
* Set URI fragment
* @param fragment fragment string
* @return request instance
*/
T fragment(String fragment);
/**
* Set URI fragment
* @param fragment UriFragment instance
* @return request instance
*/
T fragment(UriFragment fragment);
/**
* Skip URI encoding for this request
* @param skip true to skip encoding
* @return request instance
*/
T skipUriEncoding(boolean skip);Usage Examples:
// Path parameters
String response = client.get("/api/users/{id}/posts/{postId}")
.pathParam("id", "123")
.pathParam("postId", "456")
.requestEntity(String.class);
// Actual URI: /api/users/123/posts/456
// Query parameters
String response = client.get("/api/search")
.queryParam("q", "java")
.queryParam("type", "code", "docs")
.queryParam("limit", "10")
.requestEntity(String.class);
// Actual URI: /api/search?q=java&type=code&type=docs&limit=10
// Fragment
String response = client.get("/api/docs")
.fragment("section-1")
.requestEntity(String.class);
// Actual URI: /api/docs#section-1Configure HTTP headers for requests including content negotiation and custom headers.
/**
* Set a header value
* @param header header instance
* @return request instance
*/
T header(Header header);
/**
* Set a header value
* @param name header name
* @param values header values
* @return request instance
*/
T header(HeaderName name, String... values);
/**
* Configure multiple headers
* @param headers headers instance
* @return request instance
*/
T headers(Headers headers);
/**
* Configure headers using a consumer
* @param headersConsumer consumer to configure headers
* @return request instance
*/
T headers(Consumer<ClientRequestHeaders> headersConsumer);
/**
* Set Accept header for content negotiation
* @param accepted accepted media types
* @return request instance
*/
T accept(HttpMediaType... accepted);
/**
* Set Accept header for content negotiation
* @param acceptedTypes accepted media types
* @return request instance
*/
T accept(MediaType... acceptedTypes);
/**
* Set Content-Type header
* @param contentType content type
* @return request instance
*/
T contentType(MediaType contentType);Usage Examples:
import io.helidon.http.Header;
import io.helidon.http.HeaderNames;
import io.helidon.http.MediaType;
String response = client.post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.header(HeaderNames.AUTHORIZATION, "Bearer " + token)
.header(Header.create("X-Custom-Header", "value"))
.headers(headers -> {
headers.add("X-Request-ID", requestId);
headers.add("X-Client-Version", "1.0");
})
.submit(userData, String.class)
.entity();Execute requests with different patterns for handling request bodies and response types.
/**
* Execute request without entity
* @return HTTP response
*/
HttpClientResponse request();
/**
* Submit request with entity
* @param entity request entity
* @return HTTP response
*/
HttpClientResponse submit(Object entity);
/**
* Handle output stream for request body
* @param outputStreamConsumer consumer to write to output stream
* @return HTTP response
*/
HttpClientResponse outputStream(OutputStreamHandler outputStreamConsumer);
/**
* Execute request without entity and return typed response
* @param type expected response type
* @return typed response wrapper
*/
<E> ClientResponseTyped<E> request(Class<E> type);
/**
* Execute request without entity and return entity directly
* Throws exception on non-success status
* @param type expected response type
* @return response entity
*/
<E> E requestEntity(Class<E> type);
/**
* Submit request with entity and return typed response
* @param entity request entity
* @param requestedType expected response type
* @return typed response wrapper
*/
<T> ClientResponseTyped<T> submit(Object entity, Class<T> requestedType);Usage Examples:
// Simple request without entity
HttpClientResponse response = client.get("/api/users").request();
String body = response.as(String.class);
// Request with automatic entity conversion
String users = client.get("/api/users").requestEntity(String.class);
// Request with typed response
ClientResponseTyped<List<User>> typedResponse = client.get("/api/users")
.request(new GenericType<List<User>>() {});
List<User> users = typedResponse.entity();
// POST with entity
User newUser = client.post("/api/users")
.submit(userData, User.class)
.entity();
// Streaming request body
HttpClientResponse response = client.post("/api/upload")
.outputStream(outputStream -> {
// Write data to output stream
outputStream.write(data);
});Configure request-specific settings that override client defaults.
/**
* Configure TLS for this specific request
* @param tls TLS configuration
* @return request instance
*/
T tls(Tls tls);
/**
* Configure proxy for this specific request
* @param proxy proxy configuration
* @return request instance
*/
T proxy(Proxy proxy);
/**
* Configure redirect behavior for this request
* @param followRedirects true to follow redirects
* @return request instance
*/
T followRedirects(boolean followRedirects);
/**
* Configure maximum redirects for this request
* @param maxRedirects maximum redirect count
* @return request instance
*/
T maxRedirects(int maxRedirects);
/**
* Configure read timeout for this request
* @param readTimeout timeout duration
* @return request instance
*/
T readTimeout(Duration readTimeout);
/**
* Configure 100-Continue timeout for this request
* @param readContinueTimeout timeout duration
* @return request instance
*/
T readContinueTimeout(Duration readContinueTimeout);
/**
* Configure Expect: 100-Continue header
* @param sendExpectContinue true to send header
* @return request instance
*/
T sendExpectContinue(boolean sendExpectContinue);
/**
* Configure keep-alive for this request
* @param keepAlive true to enable keep-alive
* @return request instance
*/
T keepAlive(boolean keepAlive);
/**
* Use explicit connection for this request
* @param connection connection instance
* @return request instance
*/
T connection(ClientConnection connection);
/**
* Add request property for service consumption
* @param propertyName property name
* @param propertyValue property value
* @return request instance
*/
T property(String propertyName, String propertyValue);Access response data, metadata, and typed content conversion.
/**
* Get response entity for reading
* @return readable entity
*/
ReadableEntity entity();
/**
* Get response input stream (shortcut)
* @return response input stream
*/
default InputStream inputStream();
/**
* Read entity as specific type (shortcut)
* @param type target type
* @return converted entity
*/
default <T> T as(Class<T> type);
/**
* Register source listener for streaming responses
* @param sourceType source type
* @param source source instance
*/
default <T extends Source<?>> void source(GenericType<T> sourceType, T source);
/**
* Close response (may not impact connection)
*/
void close();Usage Examples:
// Access response metadata
HttpClientResponse response = client.get("/api/users").request();
Status status = response.status();
ClientResponseHeaders headers = response.headers();
Optional<MediaType> contentType = response.contentType();
long contentLength = response.contentLength();
// Read response entity
String body = response.as(String.class);
// Streaming response
try (HttpClientResponse response = client.get("/api/large-data").request()) {
try (InputStream inputStream = response.inputStream()) {
// Process stream
}
}
// Typed response
ClientResponseTyped<User> typedResponse = client.get("/api/users/123")
.request(User.class);
if (typedResponse.status().code() == 200) {
User user = typedResponse.entity();
}Common response functionality available to all response types.
/**
* Get HTTP status
* @return response status
*/
Status status();
/**
* Get response headers
* @return response headers
*/
ClientResponseHeaders headers();
/**
* Get Content-Type header
* @return content type if present
*/
Optional<MediaType> contentType();
/**
* Get Content-Length header
* @return content length or -1 if not specified
*/
long contentLength();Force specific HTTP protocol version for a request.
/**
* Force specific HTTP protocol version
* @param protocol protocol identifier (e.g., "http/1.1", "h2")
* @return request instance
*/
HttpClientRequest protocolId(String protocol);Usage Examples:
// Force HTTP/1.1
HttpClientResponse response = client.get("/api/data")
.protocolId("http/1.1")
.request();
// Force HTTP/2
HttpClientResponse response = client.get("/api/data")
.protocolId("h2")
.request();public interface HttpClientRequest extends ClientRequest<HttpClientRequest> {
HttpClientRequest protocolId(String protocol);
}
public interface ClientRequest<T> {
T uri(String uri);
T uri(URI uri);
T uri(ClientUri uri);
T path(String uri);
T pathParam(String name, String value);
T queryParam(String name, String... values);
T fragment(String fragment);
T fragment(UriFragment fragment);
T header(Header header);
T header(HeaderName name, String... values);
T headers(Headers headers);
T headers(Consumer<ClientRequestHeaders> headersConsumer);
T accept(HttpMediaType... accepted);
T accept(MediaType... acceptedTypes);
T contentType(MediaType contentType);
T tls(Tls tls);
T proxy(Proxy proxy);
T followRedirects(boolean followRedirects);
T maxRedirects(int maxRedirects);
T readTimeout(Duration readTimeout);
T readContinueTimeout(Duration readContinueTimeout);
T sendExpectContinue(boolean sendExpectContinue);
T keepAlive(boolean keepAlive);
T connection(ClientConnection connection);
T skipUriEncoding(boolean skip);
T property(String propertyName, String propertyValue);
HttpClientResponse request();
HttpClientResponse submit(Object entity);
HttpClientResponse outputStream(OutputStreamHandler outputStreamConsumer);
<E> ClientResponseTyped<E> request(Class<E> type);
<E> E requestEntity(Class<E> type);
<T> ClientResponseTyped<T> submit(Object entity, Class<T> requestedType);
}
public interface HttpClientResponse extends ClientResponseBase, AutoCloseable {
ReadableEntity entity();
default InputStream inputStream();
default <T> T as(Class<T> type);
default <T extends Source<?>> void source(GenericType<T> sourceType, T source);
void close();
}
public interface ClientResponseTyped<E> extends ClientResponseBase {
E entity();
}
public interface ClientResponseBase {
Status status();
ClientResponseHeaders headers();
Optional<MediaType> contentType();
long contentLength();
}
@FunctionalInterface
public interface OutputStreamHandler {
void handle(OutputStream outputStream) throws IOException;
}Install with Tessl CLI
npx tessl i tessl/maven-io-helidon-webclient--helidon-webclient