CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-helidon-webserver--helidon-webserver

High-performance HTTP server implementation built on Java 21 Virtual Threads for Helidon microservices framework

Pending
Overview
Eval results
Files

http-services.mddocs/

HTTP Services and Features

Modular service system for creating reusable HTTP components, middleware, and features that can be registered with routing for building scalable web applications.

Capabilities

HttpService Interface

Interface for creating reusable HTTP service components that encapsulate related routing logic.

/**
 * Interface for HTTP services that can be registered with routing.
 */
interface HttpService {
    /**
     * Configure routing rules for this service.
     * @param rules routing rules to configure
     */
    void routing(HttpRules rules);
}

Usage Examples:

import io.helidon.webserver.http.HttpService;
import io.helidon.webserver.http.HttpRules;

// User management service
class UserService implements HttpService {
    @Override
    public void routing(HttpRules rules) {
        rules.get("/", this::getAllUsers)
             .get("/{id}", this::getUserById)
             .post("/", this::createUser)
             .put("/{id}", this::updateUser)
             .delete("/{id}", this::deleteUser);
    }
    
    private void getAllUsers(ServerRequest req, ServerResponse res) {
        // Implementation for getting all users
        res.send("All users");
    }
    
    private void getUserById(ServerRequest req, ServerResponse res) {
        String id = req.path().pathParameters().get("id");
        res.send("User: " + id);
    }
    
    private void createUser(ServerRequest req, ServerResponse res) {
        // Implementation for creating user
        res.status(201).send("User created");
    }
    
    private void updateUser(ServerRequest req, ServerResponse res) {
        String id = req.path().pathParameters().get("id");
        res.send("User " + id + " updated");
    }
    
    private void deleteUser(ServerRequest req, ServerResponse res) {
        String id = req.path().pathParameters().get("id");
        res.status(204).send();
    }
}

// Register service with routing
HttpService userService = new UserService();
HttpRouting routing = HttpRouting.builder()
    .register("/api/users", userService)
    .build();

HttpFeature Interface

Interface for creating HTTP features that provide cross-cutting functionality across multiple routes.

/**
 * Interface for HTTP features that enhance routing functionality.
 */
interface HttpFeature {
    /**
     * Setup feature with routing builder.
     * @param routing routing builder to configure
     */
    void setup(HttpRouting.Builder routing);
}

Usage Examples:

import io.helidon.webserver.http.HttpFeature;

// CORS feature
class CorsFeature implements HttpFeature {
    private final String allowedOrigins;
    private final String allowedMethods;
    
    public CorsFeature(String allowedOrigins, String allowedMethods) {
        this.allowedOrigins = allowedOrigins;
        this.allowedMethods = allowedMethods;
    }
    
    @Override
    public void setup(HttpRouting.Builder routing) {
        // Add CORS filter
        routing.addFilter((chain, req, res) -> {
            res.header("Access-Control-Allow-Origin", allowedOrigins)
               .header("Access-Control-Allow-Methods", allowedMethods)
               .header("Access-Control-Allow-Headers", "Content-Type, Authorization");
            
            if ("OPTIONS".equals(req.method().text())) {
                res.status(200).send();
            } else {
                chain.proceed();
            }
        });
    }
}

// Logging feature
class LoggingFeature implements HttpFeature {
    @Override
    public void setup(HttpRouting.Builder routing) {
        routing.addFilter((chain, req, res) -> {
            long startTime = System.currentTimeMillis();
            System.out.println("Request: " + req.method() + " " + req.path().path());
            
            chain.proceed();
            
            long duration = System.currentTimeMillis() - startTime;
            System.out.println("Response time: " + duration + "ms");
        });
    }
}

// Use features in routing
HttpRouting routing = HttpRouting.builder()
    .addFeature(new CorsFeature("*", "GET,POST,PUT,DELETE"))
    .addFeature(new LoggingFeature())
    .get("/api/data", (req, res) -> res.send("Data"))
    .build();

Filter Interface

Interface for creating HTTP filters that provide request/response processing middleware.

/**
 * Interface for HTTP filters that process requests and responses.
 */
interface Filter {
    /**
     * Filter request and response.
     * @param chain filter chain to continue processing
     * @param req routing request
     * @param res routing response
     */
    void filter(FilterChain chain, RoutingRequest req, RoutingResponse res);
}

FilterChain Interface

Interface for controlling filter chain execution.

/**
 * Chain of filters for request processing.
 */
interface FilterChain {
    /**
     * Continue to next filter or handler in the chain.
     */
    void proceed();
}

Usage Examples:

import io.helidon.webserver.http.Filter;
import io.helidon.webserver.http.FilterChain;

// Authentication filter
Filter authFilter = (chain, req, res) -> {
    Optional<String> authHeader = req.headers().first("Authorization");
    
    if (authHeader.isPresent() && authHeader.get().startsWith("Bearer ")) {
        String token = authHeader.get().substring(7);
        
        if (isValidToken(token)) {
            // Add user info to context
            req.context().register("userId", extractUserId(token));
            chain.proceed(); // Continue to next filter/handler
        } else {
            res.status(401).send("Invalid token");
        }
    } else {
        res.status(401).send("Authorization required");
    }
};

// Request timing filter
Filter timingFilter = (chain, req, res) -> {
    long startTime = System.currentTimeMillis();
    
    chain.proceed();
    
    long duration = System.currentTimeMillis() - startTime;
    res.header("X-Response-Time", duration + "ms");
};

// Rate limiting filter
Filter rateLimitFilter = (chain, req, res) -> {
    String clientIp = req.remoteAddress();
    
    if (isRateLimited(clientIp)) {
        res.status(429).send("Rate limit exceeded");
    } else {
        recordRequest(clientIp);
        chain.proceed();
    }
};

// Register filters
HttpRouting routing = HttpRouting.builder()
    .addFilter(rateLimitFilter)   // Applied first
    .addFilter(authFilter)        // Applied second
    .addFilter(timingFilter)      // Applied third
    .get("/api/secure", (req, res) -> {
        String userId = req.context().get("userId", String.class).orElse("unknown");
        res.send("Secure data for user: " + userId);
    })
    .build();

ErrorHandler Interface

Interface for handling exceptions thrown during request processing.

/**
 * Interface for handling exceptions of specific types.
 * @param <T> exception type
 */
interface ErrorHandler<T extends Throwable> {
    /**
     * Handle exception and generate error response.
     * @param req server request
     * @param res server response
     * @param throwable the exception to handle
     */
    void handle(ServerRequest req, ServerResponse res, T throwable);
}

Usage Examples:

import io.helidon.webserver.http.ErrorHandler;

// Validation error handler
ErrorHandler<IllegalArgumentException> validationErrorHandler = 
    (req, res, ex) -> {
        res.status(400)
           .contentType(MediaType.APPLICATION_JSON)
           .send(Map.of(
               "error", "Validation Error",
               "message", ex.getMessage(),
               "timestamp", System.currentTimeMillis()
           ));
    };

// Database error handler
ErrorHandler<SQLException> databaseErrorHandler = 
    (req, res, ex) -> {
        System.err.println("Database error: " + ex.getMessage());
        res.status(500)
           .send("Database temporarily unavailable");
    };

// Security error handler
ErrorHandler<SecurityException> securityErrorHandler = 
    (req, res, ex) -> {
        String requestId = UUID.randomUUID().toString();
        System.err.println("Security violation [" + requestId + "]: " + ex.getMessage());
        
        res.status(403)
           .header("X-Request-ID", requestId)
           .send("Access denied");
    };

// Generic error handler
ErrorHandler<Exception> genericErrorHandler = 
    (req, res, ex) -> {
        String requestId = UUID.randomUUID().toString();
        System.err.println("Unexpected error [" + requestId + "]: " + ex.getMessage());
        
        res.status(500)
           .header("X-Request-ID", requestId)
           .send("Internal server error");
    };

// Register error handlers
HttpRouting routing = HttpRouting.builder()
    .error(IllegalArgumentException.class, validationErrorHandler)
    .error(SQLException.class, databaseErrorHandler)
    .error(SecurityException.class, securityErrorHandler)
    .error(Exception.class, genericErrorHandler) // Catch-all
    
    .get("/api/users/{id}", (req, res) -> {
        String id = req.path().pathParameters().get("id");
        
        // Validation that might throw IllegalArgumentException
        if (!id.matches("\\d+")) {
            throw new IllegalArgumentException("ID must be numeric");
        }
        
        // Database operation that might throw SQLException
        User user = userRepository.findById(Long.parseLong(id));
        res.send(user);
    })
    .build();

Service Registration Patterns

Multiple approaches for registering HTTP services and organizing application logic.

/**
 * Service registration methods in HttpRouting.Builder
 */
interface Builder {
    /**
     * Register services without path prefix.
     * @param service services to register
     * @return updated builder
     */
    Builder register(HttpService... service);
    
    /**
     * Register services with path prefix.
     * @param path path prefix for all service routes
     * @param service services to register
     * @return updated builder
     */
    Builder register(String path, HttpService... service);
    
    /**
     * Register service suppliers for lazy initialization.
     * @param service service supplier
     * @return updated builder
     */
    default Builder register(Supplier<? extends HttpService> service);
    
    /**
     * Register multiple service suppliers.
     * @param services list of service suppliers
     * @return updated builder
     */
    default Builder register(List<Supplier<? extends HttpService>> services);
}

Usage Examples:

// Multiple service classes
class UserService implements HttpService {
    @Override
    public void routing(HttpRules rules) {
        rules.get("/", (req, res) -> res.send("Users"))
             .get("/{id}", (req, res) -> res.send("User details"));
    }
}

class OrderService implements HttpService {
    @Override
    public void routing(HttpRules rules) {
        rules.get("/", (req, res) -> res.send("Orders"))
             .post("/", (req, res) -> res.status(201).send("Order created"));
    }
}

class ProductService implements HttpService {
    @Override
    public void routing(HttpRules rules) {
        rules.get("/", (req, res) -> res.send("Products"))
             .get("/{id}", (req, res) -> res.send("Product details"));
    }
}

// Register services with different approaches
HttpRouting routing = HttpRouting.builder()
    // Direct registration with path prefixes
    .register("/api/users", new UserService())
    .register("/api/orders", new OrderService())
    .register("/api/products", new ProductService())
    
    // Multiple services with same prefix
    .register("/admin", new UserService(), new OrderService())
    
    // Lazy service registration
    .register(() -> new UserService())
    .register("/api/v2/users", () -> new UserService())
    
    // Service list registration
    .register(Arrays.asList(
        () -> new UserService(),
        () -> new OrderService(),
        () -> new ProductService()
    ))
    
    .build();

Advanced Service Patterns

Service Composition

// Base service with common functionality
abstract class BaseService implements HttpService {
    protected void addCommonRoutes(HttpRules rules) {
        rules.get("/health", (req, res) -> res.send("OK"))
             .get("/version", (req, res) -> res.send("1.0.0"));
    }
}

// Specific services extending base functionality
class UserService extends BaseService {
    @Override
    public void routing(HttpRules rules) {
        addCommonRoutes(rules);
        
        rules.get("/", this::getAllUsers)
             .get("/{id}", this::getUserById)
             .post("/", this::createUser);
    }
    
    // Implementation methods...
}

// Service with dependency injection
class OrderService implements HttpService {
    private final OrderRepository orderRepository;
    private final NotificationService notificationService;
    
    public OrderService(OrderRepository orderRepository, 
                       NotificationService notificationService) {
        this.orderRepository = orderRepository;
        this.notificationService = notificationService;
    }
    
    @Override
    public void routing(HttpRules rules) {
        rules.post("/", this::createOrder)
             .get("/{id}", this::getOrder)
             .put("/{id}/status", this::updateOrderStatus);
    }
    
    private void createOrder(ServerRequest req, ServerResponse res) {
        Order order = req.entity().as(Order.class);
        Order saved = orderRepository.save(order);
        notificationService.sendOrderConfirmation(saved);
        res.status(201).send(saved);
    }
}

Feature Composition

// Composable feature for API versioning
class ApiVersionFeature implements HttpFeature {
    private final String version;
    
    public ApiVersionFeature(String version) {
        this.version = version;
    }
    
    @Override
    public void setup(HttpRouting.Builder routing) {
        routing.addFilter((chain, req, res) -> {
            res.header("API-Version", version);
            chain.proceed();
        });
    }
}

// Security feature with role-based access
class SecurityFeature implements HttpFeature {
    private final SecurityManager securityManager;
    
    public SecurityFeature(SecurityManager securityManager) {
        this.securityManager = securityManager;
    }
    
    @Override
    public void setup(HttpRouting.Builder routing) {
        routing.addFilter((chain, req, res) -> {
            if (requiresAuthentication(req)) {
                if (securityManager.authenticate(req)) {
                    chain.proceed();
                } else {
                    res.status(401).send("Unauthorized");
                }
            } else {
                chain.proceed();
            }
        });
    }
}

// Metrics feature
class MetricsFeature implements HttpFeature {
    private final MeterRegistry meterRegistry;
    
    public MetricsFeature(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }
    
    @Override
    public void setup(HttpRouting.Builder routing) {
        routing.addFilter((chain, req, res) -> {
            Timer.Sample sample = Timer.start(meterRegistry);
            
            try {
                chain.proceed();
            } finally {
                sample.stop(Timer.builder("http.requests")
                    .tag("method", req.method().text())
                    .tag("path", req.path().path())
                    .register(meterRegistry));
            }
        });
    }
}

// Combine features
HttpRouting routing = HttpRouting.builder()
    .addFeature(new ApiVersionFeature("v1"))
    .addFeature(new SecurityFeature(securityManager))
    .addFeature(new MetricsFeature(meterRegistry))
    .register("/api/users", userService)
    .register("/api/orders", orderService)
    .build();

Service Factory Pattern

// Service factory for creating configured services
class ServiceFactory {
    private final DataSource dataSource;
    private final CacheManager cacheManager;
    
    public ServiceFactory(DataSource dataSource, CacheManager cacheManager) {
        this.dataSource = dataSource;
        this.cacheManager = cacheManager;
    }
    
    public UserService createUserService() {
        return new UserService(
            new UserRepository(dataSource),
            new UserCache(cacheManager)
        );
    }
    
    public OrderService createOrderService() {
        return new OrderService(
            new OrderRepository(dataSource),
            new NotificationService()
        );
    }
}

// Configuration-driven service registration
class ApplicationConfig {
    public HttpRouting createRouting() {
        ServiceFactory factory = new ServiceFactory(dataSource, cacheManager);
        
        return HttpRouting.builder()
            .addFeature(new CorsFeature("*", "GET,POST,PUT,DELETE"))
            .addFeature(new LoggingFeature())
            
            .register("/api/v1/users", factory::createUserService)
            .register("/api/v1/orders", factory::createOrderService)
            
            .error(ValidationException.class, this::handleValidationError)
            .error(Exception.class, this::handleGenericError)
            
            .build();
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-io-helidon-webserver--helidon-webserver

docs

configuration.md

http-routing.md

http-services.md

http1-protocol.md

index.md

request-response.md

server-management.md

spi.md

tile.json