-
Notifications
You must be signed in to change notification settings - Fork 98
Description
Use case
Currently, Powertools for AWS Lambda (Java) provides individual utilities like Logging, Tracing, Metrics, and other features through AspectJ annotations and static methods. While effective, this approach lacks a unified and modern functional interface for applying multiple Powertools utilities to Lambda handlers without relying on AspectJ annotations.
Developers need a solution that offers:
- A unified functional API to compose multiple Powertools features (logging, tracing, metrics, validation, etc.)
- Type-safe middleware composition that works across all Lambda handler types (RequestHandler, RequestStreamHandler, etc.)
- Clean separation between business logic and cross-cutting concerns without AspectJ dependencies
- Flexible composition allowing different orders and combinations of middlewares
- Modern Java functional programming patterns that feel idiomatic to Java developers
This would provide an alternative to the current AspectJ annotation-based approach while maintaining the same powerful utility features.
Solution/User Experience
Introduce a middleware chain API that allows functional composition of Powertools features. The design below suggests an implementation of the Chain of Responsibility software design pattern:
@FunctionalInterface
public interface Middleware<T, R> {
R apply(T input, Context context, BiFunction<T, Context, R> next);
}
public class MiddlewareChain<T, R> {
public MiddlewareChain<T, R> use(Middleware<T, R> middleware) { /* ... */ }
public R execute(T input, Context context, BiFunction<T, Context, R> handler) { /* ... */ }
}
public class PowertoolsMiddlewares {
public static <T, R> Middleware<T, R> logging() { /* ... */ }
public static <T, R> Middleware<T, R> tracing(String serviceName) { /* ... */ }
public static <T, R> Middleware<T, R> metrics(String namespace) { /* ... */ }
}
Usage example:
public class OrderHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
private final MiddlewareChain<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> chain =
new MiddlewareChain<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent>()
.use(PowertoolsMiddlewares.logging())
.use(PowertoolsMiddlewares.tracing("OrderService"))
.use(PowertoolsMiddlewares.metrics("Orders"));
@Override
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
return chain.execute(input, context, this::processOrder);
}
private APIGatewayProxyResponseEvent processOrder(APIGatewayProxyRequestEvent request, Context context) {
// Business logic here
return APIGatewayProxyResponseEvent.builder()
.withStatusCode(200)
.withBody("{\"message\": \"Order processed\"}")
.build();
}
}
Benefits:
- Type-safe: Works with any Lambda handler type through generics
- Composable: Middlewares can be combined in any order
- Functional: Leverages modern Java functional programming patterns
- Consistent: Same API works for RequestHandler, RequestStreamHandler, etc.
- Flexible: Easy to add custom middlewares or modify the chain
Alternative solutions
Decorator pattern: Wrap handlers with individual decorators
- Pros: Object-oriented approach, familiar pattern
- Cons: More verbose, harder to compose multiple decorators, requires creating wrapper classes for each feature
Aspect-Oriented Programming (AOP): Frameworks like Spring AOP are too heavy for Lambda environments and introduce additional dependencies that may not be suitable for serverless architectures.
Acknowledgment
- This feature request meets Powertools for AWS Lambda (Java) Tenets
- Should this be considered in other Powertools for AWS Lambda languages? i.e. Python, TypeScript, and .NET
Disclaimer: After creating an issue, please wait until it is triaged and confirmed by a maintainer before implementing it. This will reduce amount of rework and the chance that a pull request gets rejected.
Future readers: Please react with 👍 and your use case to help us understand customer demand.
Sub-issues
Metadata
Metadata
Assignees
Labels
Type
Projects
Status