Skip to content

Commit 40adb7d

Browse files
committed
add middleware composition section
1 parent b8bedc7 commit 40adb7d

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

docs/features/event-handler/rest.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,25 @@ During the middleware execution chain, the response object (`reqCtx.res`) can be
427427
other middleware or the route handler. When you destructure the request context, you capture
428428
a reference to the response object as it existed at that moment, not the current response.
429429

430+
#### Composing middleware
431+
432+
You can create reusable middleware stacks by using the `composeMiddleware` function to combine
433+
multiple middleware into a single middleware function. This is useful for creating standardized
434+
middleware combinations that can be shared across different routes or applications.
435+
436+
=== "index.ts"
437+
438+
```ts hl_lines="25-26 32 35"
439+
--8<-- "examples/snippets/event-handler/rest/advanced_mw_compose_middleware.ts:3"
440+
```
441+
442+
The `composeMiddleware` function maintains the same execution order as if you had applied the
443+
middleware individually, following the onion pattern where middleware execute in order during
444+
pre-processing and in reverse order during post-processing.
445+
446+
!!! note "Composition order"
447+
Unlike traditional function composition which typically works right-to-left, `composeMiddleware` follows the convention used by most web frameworks and executes middleware left-to-right (first to last in the array). This means `composeMiddleware([a, b, c])` executes middleware `a` first, then `b`, then `c`.
448+
430449
### Fine grained responses
431450

432451
You can use the Web API's `Response` object to have full control over the response. For
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
declare const getAllTodos: () => Promise<any[]>;
2+
declare const putTodo: (body: any) => Promise<any>;
3+
4+
import {
5+
composeMiddleware,
6+
Router,
7+
} from '@aws-lambda-powertools/event-handler/experimental-rest';
8+
import type { Middleware } from '@aws-lambda-powertools/event-handler/types';
9+
import { Logger } from '@aws-lambda-powertools/logger';
10+
import type { Context } from 'aws-lambda';
11+
12+
const logger = new Logger();
13+
14+
// Individual middleware functions
15+
const logging: Middleware = async (params, reqCtx, next) => {
16+
logger.info(`Request: ${reqCtx.request.method} ${reqCtx.request.url}`);
17+
await next();
18+
logger.info(`Response: ${reqCtx.res.status}`);
19+
};
20+
21+
const cors: Middleware = async (params, reqCtx, next) => {
22+
await next();
23+
reqCtx.res.headers.set('Access-Control-Allow-Origin', '*');
24+
reqCtx.res.headers.set(
25+
'Access-Control-Allow-Methods',
26+
'GET, POST, PUT, DELETE'
27+
);
28+
};
29+
30+
const rateLimit: Middleware = async (params, reqCtx, next) => {
31+
// Rate limiting logic would go here
32+
reqCtx.res.headers.set('X-RateLimit-Limit', '100');
33+
await next();
34+
};
35+
36+
// Compose middleware stack for all requests
37+
const apiMiddleware = composeMiddleware([logging, cors, rateLimit]);
38+
39+
const app = new Router();
40+
41+
// Use composed middleware globally
42+
app.use(apiMiddleware);
43+
44+
app.get('/todos', async () => {
45+
const todos = await getAllTodos();
46+
return { todos };
47+
});
48+
49+
app.post('/todos', async (params, { request }) => {
50+
const body = await request.json();
51+
const todo = await putTodo(body);
52+
return todo;
53+
});
54+
55+
export const handler = async (event: unknown, context: Context) => {
56+
return await app.resolve(event, context);
57+
};

0 commit comments

Comments
 (0)