High-performance HTTP server implementation built on Java 21 Virtual Threads for Helidon microservices framework
—
Complete HTTP request and response interfaces with entity handling, headers, parameters, and content negotiation for comprehensive HTTP communication.
The core interface for processing HTTP requests and generating responses.
/**
* Interface for handling HTTP requests.
*/
interface Handler {
/**
* Handle HTTP request and generate response.
* @param req server request
* @param res server response
*/
void handle(ServerRequest req, ServerResponse res);
/**
* Create handler from consumer function.
* @param handler consumer that processes the request
* @return new handler instance
*/
static Handler create(Consumer<ServerRequest> handler);
/**
* Create handler from function that returns response data.
* @param handler function that processes request and returns response data
* @return new handler instance
*/
static Handler create(Function<ServerRequest, ?> handler);
/**
* Create handler from supplier that returns response data.
* @param handler supplier that returns response data
* @return new handler instance
*/
static Handler create(Supplier<?> handler);
}Usage Examples:
import io.helidon.webserver.http.Handler;
// Lambda handler
Handler lambdaHandler = (req, res) -> {
res.send("Hello from lambda");
};
// Consumer-based handler
Handler consumerHandler = Handler.create(req -> {
System.out.println("Processing request: " + req.method());
});
// Function-based handler
Handler functionHandler = Handler.create(req -> {
return "Response for " + req.path().path();
});
// Supplier-based handler
Handler supplierHandler = Handler.create(() -> {
return "Fixed response";
});Interface for accessing HTTP request data, headers, parameters, and body content.
/**
* HTTP server request interface.
*/
interface ServerRequest extends HttpRequest {
/**
* Get request path information.
* @return path information with parameters and matchers
*/
ServerRequestPath path();
/**
* Get request query parameters.
* @return query parameters
*/
Parameters query();
/**
* Get request headers.
* @return request headers
*/
ServerRequestHeaders headers();
/**
* Get request entity (body).
* @return request entity
*/
ServerRequestEntity entity();
/**
* Get HTTP method.
* @return HTTP method
*/
Method method();
/**
* Get request URI.
* @return request URI
*/
UriInfo requestedUri();
/**
* Get local address of the connection.
* @return local address
*/
String localAddress();
/**
* Get local port of the connection.
* @return local port
*/
int localPort();
/**
* Get remote address of the connection.
* @return remote address
*/
String remoteAddress();
/**
* Get remote port of the connection.
* @return remote port
*/
int remotePort();
/**
* Check if connection is secure (TLS).
* @return true if secure connection
*/
boolean isSecure();
/**
* Get server request context.
* @return request context
*/
Context context();
}Usage Examples:
Handler requestInfoHandler = (req, res) -> {
// Access request information
String method = req.method().text();
String path = req.path().path();
String remoteAddr = req.remoteAddress();
boolean secure = req.isSecure();
// Access path parameters
Map<String, String> pathParams = req.path().pathParameters().toMap();
String userId = pathParams.get("id");
// Access query parameters
Optional<String> filter = req.query().first("filter");
List<String> tags = req.query().all("tag");
// Access headers
Optional<String> contentType = req.headers().contentType()
.map(MediaType::text);
Optional<String> userAgent = req.headers().first("User-Agent");
// Build response
String info = String.format(
"Method: %s, Path: %s, Remote: %s, Secure: %s",
method, path, remoteAddr, secure
);
res.send(info);
};Interface for generating HTTP responses with status codes, headers, and body content.
/**
* HTTP server response interface.
*/
interface ServerResponse {
/**
* Set response status code.
* @param status HTTP status
* @return this response for chaining
*/
ServerResponse status(Status status);
/**
* Set response status code.
* @param statusCode HTTP status code
* @return this response for chaining
*/
ServerResponse status(int statusCode);
/**
* Add response header.
* @param name header name
* @param value header value
* @return this response for chaining
*/
ServerResponse header(String name, String value);
/**
* Add response header with multiple values.
* @param name header name
* @param values header values
* @return this response for chaining
*/
ServerResponse header(String name, String... values);
/**
* Set response headers.
* @param headers headers to set
* @return this response for chaining
*/
ServerResponse headers(WritableHeaders<?> headers);
/**
* Set content type.
* @param contentType media type
* @return this response for chaining
*/
ServerResponse contentType(MediaType contentType);
/**
* Send response with string content.
* @param entity response content
*/
void send(String entity);
/**
* Send response with byte array content.
* @param entity response content
*/
void send(byte[] entity);
/**
* Send response with input stream content.
* @param entity response content
*/
void send(InputStream entity);
/**
* Send response with object content (uses media support for serialization).
* @param entity response object
*/
void send(Object entity);
/**
* Send empty response.
*/
void send();
/**
* Re-route request to different path.
* @param path new path
*/
void reroute(String path);
/**
* Re-route request to different path with query parameters.
* @param path new path
* @param queryParams query parameters
*/
void reroute(String path, UriQuery queryParams);
/**
* Get response headers for modification.
* @return response headers
*/
ServerResponseHeaders headers();
/**
* Check if response headers have been sent.
* @return true if headers sent
*/
boolean headersSent();
/**
* Get server response context.
* @return response context
*/
Context context();
}Usage Examples:
import io.helidon.http.Status;
import io.helidon.http.MediaType;
// Basic response handling
Handler basicHandler = (req, res) -> {
res.status(Status.OK_200)
.contentType(MediaType.TEXT_PLAIN)
.send("Hello World");
};
// JSON response
Handler jsonHandler = (req, res) -> {
Map<String, Object> data = Map.of(
"message", "Hello",
"timestamp", System.currentTimeMillis()
);
res.status(Status.OK_200)
.contentType(MediaType.APPLICATION_JSON)
.send(data); // Automatically serialized to JSON
};
// Custom headers
Handler customHeadersHandler = (req, res) -> {
res.status(Status.OK_200)
.header("X-Custom-Header", "CustomValue")
.header("Cache-Control", "no-cache", "no-store")
.contentType(MediaType.TEXT_HTML)
.send("<h1>Custom Response</h1>");
};
// File download
Handler downloadHandler = (req, res) -> {
try {
Path filePath = Paths.get("data.pdf");
byte[] fileContent = Files.readAllBytes(filePath);
res.status(Status.OK_200)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment; filename=data.pdf")
.send(fileContent);
} catch (IOException e) {
res.status(Status.INTERNAL_SERVER_ERROR_500)
.send("File not found");
}
};
// Streaming response
Handler streamHandler = (req, res) -> {
try {
InputStream stream = new FileInputStream("large-file.txt");
res.status(Status.OK_200)
.contentType(MediaType.TEXT_PLAIN)
.send(stream); // Automatically streams content
} catch (FileNotFoundException e) {
res.status(Status.NOT_FOUND_404).send("File not found");
}
};Interface for accessing request body content with various content types.
/**
* Entity part of server request for accessing request body.
*/
interface ServerRequestEntity {
/**
* Get entity as string.
* @return entity content as string
*/
String as(Class<String> type);
/**
* Get entity as byte array.
* @return entity content as byte array
*/
byte[] as(Class<byte[]> type);
/**
* Get entity as input stream.
* @return entity content as input stream
*/
InputStream as(Class<InputStream> type);
/**
* Get entity as specific type using media support.
* @param type target type
* @param <T> type parameter
* @return entity converted to target type
*/
<T> T as(Class<T> type);
/**
* Get entity as generic type using media support.
* @param type generic type token
* @param <T> type parameter
* @return entity converted to target type
*/
<T> T as(GenericType<T> type);
/**
* Check if entity is available.
* @return true if entity is present
*/
boolean hasEntity();
/**
* Get entity content type.
* @return media type of entity
*/
Optional<MediaType> contentType();
/**
* Get entity content length.
* @return content length if known
*/
OptionalLong contentLength();
}Usage Examples:
// Handle different content types
Handler entityHandler = (req, res) -> {
ServerRequestEntity entity = req.entity();
if (!entity.hasEntity()) {
res.status(Status.BAD_REQUEST_400).send("Request body required");
return;
}
Optional<MediaType> contentType = entity.contentType();
if (contentType.isPresent()) {
if (MediaType.APPLICATION_JSON.test(contentType.get())) {
// Handle JSON
Map<String, Object> jsonData = entity.as(Map.class);
res.send("Received JSON: " + jsonData);
} else if (MediaType.TEXT_PLAIN.test(contentType.get())) {
// Handle text
String textData = entity.as(String.class);
res.send("Received text: " + textData);
} else if (MediaType.APPLICATION_OCTET_STREAM.test(contentType.get())) {
// Handle binary data
byte[] binaryData = entity.as(byte[].class);
res.send("Received " + binaryData.length + " bytes");
} else {
res.status(Status.UNSUPPORTED_MEDIA_TYPE_415)
.send("Unsupported content type");
}
} else {
// Default handling
String content = entity.as(String.class);
res.send("Received: " + content);
}
};
// Custom object deserialization
Handler userHandler = (req, res) -> {
try {
User user = req.entity().as(User.class); // Auto-deserialize JSON to User
// Process user object
res.status(Status.CREATED_201).send("User created: " + user.getName());
} catch (Exception e) {
res.status(Status.BAD_REQUEST_400).send("Invalid user data");
}
};Interface for accessing path information, parameters, and matching details.
/**
* Server request path information.
*/
interface ServerRequestPath {
/**
* Get absolute path of the request.
* @return absolute path
*/
String path();
/**
* Get path parameters extracted from path pattern.
* @return path parameters
*/
Parameters pathParameters();
/**
* Get matched path pattern.
* @return path pattern that matched this request
*/
Optional<String> pathPattern();
/**
* Get path matcher used for matching.
* @return path matcher
*/
Optional<PathMatcher> pathMatcher();
/**
* Get remaining path after matching.
* @return remaining unmatched path
*/
String remainingPath();
}Interface for accessing query and path parameters with type conversion.
/**
* Interface for accessing parameters with type conversion.
*/
interface Parameters {
/**
* Get first parameter value.
* @param name parameter name
* @return optional parameter value
*/
Optional<String> first(String name);
/**
* Get all parameter values.
* @param name parameter name
* @return list of parameter values
*/
List<String> all(String name);
/**
* Get parameter value or default.
* @param name parameter name
* @param defaultValue default value if parameter not found
* @return parameter value or default
*/
String value(String name, String defaultValue);
/**
* Check if parameter exists.
* @param name parameter name
* @return true if parameter exists
*/
boolean contains(String name);
/**
* Get all parameter names.
* @return set of parameter names
*/
Set<String> names();
/**
* Convert to map.
* @return map of parameter names to first values
*/
Map<String, String> toMap();
/**
* Convert to multi-value map.
* @return map of parameter names to all values
*/
Map<String, List<String>> toMultiMap();
}Usage Examples:
Handler parameterHandler = (req, res) -> {
// Path parameters (from /users/{id}/posts/{postId})
Parameters pathParams = req.path().pathParameters();
String userId = pathParams.first("id").orElse("unknown");
String postId = pathParams.first("postId").orElse("unknown");
// Query parameters (?filter=active&tag=java&tag=web)
Parameters queryParams = req.query();
String filter = queryParams.value("filter", "all");
List<String> tags = queryParams.all("tag");
boolean hasSearch = queryParams.contains("search");
// Convert to maps for easier processing
Map<String, String> pathMap = pathParams.toMap();
Map<String, List<String>> queryMap = queryParams.toMultiMap();
String response = String.format(
"User: %s, Post: %s, Filter: %s, Tags: %s",
userId, postId, filter, tags
);
res.send(response);
};Handler contentNegotiationHandler = (req, res) -> {
Optional<String> acceptHeader = req.headers().first("Accept");
Map<String, Object> data = Map.of(
"message", "Hello World",
"timestamp", System.currentTimeMillis()
);
if (acceptHeader.isPresent()) {
String accept = acceptHeader.get();
if (accept.contains("application/json")) {
res.contentType(MediaType.APPLICATION_JSON).send(data);
} else if (accept.contains("application/xml")) {
res.contentType(MediaType.APPLICATION_XML).send(toXml(data));
} else if (accept.contains("text/html")) {
res.contentType(MediaType.TEXT_HTML)
.send("<h1>Hello World</h1><p>Timestamp: " + data.get("timestamp") + "</p>");
} else {
res.contentType(MediaType.TEXT_PLAIN)
.send("Hello World at " + data.get("timestamp"));
}
} else {
// Default to JSON
res.contentType(MediaType.APPLICATION_JSON).send(data);
}
};Handler validationHandler = (req, res) -> {
// Validate required headers
if (!req.headers().contains("Authorization")) {
res.status(Status.UNAUTHORIZED_401)
.send("Authorization header required");
return;
}
// Validate path parameters
String id = req.path().pathParameters().first("id").orElse("");
if (id.isEmpty() || !id.matches("\\d+")) {
res.status(Status.BAD_REQUEST_400)
.send("Invalid ID parameter");
return;
}
// Validate query parameters
Optional<String> limit = req.query().first("limit");
if (limit.isPresent()) {
try {
int limitValue = Integer.parseInt(limit.get());
if (limitValue < 1 || limitValue > 100) {
res.status(Status.BAD_REQUEST_400)
.send("Limit must be between 1 and 100");
return;
}
} catch (NumberFormatException e) {
res.status(Status.BAD_REQUEST_400)
.send("Invalid limit parameter");
return;
}
}
// Process valid request
res.send("Valid request processed");
};Handler streamingHandler = (req, res) -> {
res.status(Status.OK_200)
.contentType(MediaType.TEXT_PLAIN)
.header("Transfer-Encoding", "chunked");
// Stream large dataset
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(res.outputStream()))) {
for (int i = 0; i < 1000; i++) {
writer.write("Data chunk " + i + "\n");
writer.flush();
// Simulate processing delay
Thread.sleep(10);
}
} catch (Exception e) {
// Handle streaming errors
res.status(Status.INTERNAL_SERVER_ERROR_500)
.send("Streaming error");
}
};Handler contextHandler = (req, res) -> {
Context requestContext = req.context();
// Store data in request context
requestContext.register("startTime", System.currentTimeMillis());
requestContext.register("requestId", UUID.randomUUID().toString());
// Access context data
String requestId = requestContext.get("requestId", String.class)
.orElse("unknown");
res.header("X-Request-ID", requestId)
.send("Request processed with ID: " + requestId);
};Install with Tessl CLI
npx tessl i tessl/maven-io-helidon-webserver--helidon-webserver