Skip to content

Commit 72cf1cd

Browse files
authored
docs(event-handler): update to new APIs before release (#4542)
1 parent e53aa88 commit 72cf1cd

24 files changed

+88
-62
lines changed

docs/features/event-handler/rest.md

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ Please [check this issue](https://github.com/aws-powertools/powertools-lambda-ty
128128

129129
### Accessing request details
130130

131-
You can access request details such as headers, query parameters, and body using the `Request` object provided to your route handlers and middleware functions via `reqCtx.request`.
131+
You can access request details such as headers, query parameters, and body using the `Request` object provided to your route handlers and middleware functions via `reqCtx.req`.
132132

133133
### Handling not found routes
134134

@@ -148,6 +148,8 @@ You can use the `errorHandler()` method as a higher-order function or class meth
148148

149149
This allows you to catch and return custom error responses, or perform any other error handling logic you need.
150150

151+
Error handlers receive the error object and the request context as arguments, and can return a [`Response` object](#returning-response-objects) or a JavaScript object that will be auto-serialized as per the [response auto-serialization](#response-auto-serialization) section.
152+
151153
!!! tip "You can also pass a list of error classes to the `errorHandler()` method."
152154

153155
=== "index.ts"
@@ -158,15 +160,17 @@ This allows you to catch and return custom error responses, or perform any other
158160

159161
### Throwing HTTP errors
160162

161-
You can throw HTTP errors in your route handlers to return specific HTTP status codes and messages. Event Handler provides a set of built-in HTTP error classes that you can use to throw common HTTP errors.
163+
You can throw HTTP errors in your route handlers to stop execution and return specific HTTP status codes and messages. Event Handler provides a set of built-in HTTP error classes that you can use to throw common HTTP errors.
162164

163165
This ensures that your Lambda function doesn't fail but returns a well-defined HTTP error response to the client.
164166

165167
If you need to send custom headers or a different response structure/code, you can use the [Response](#returning-response-objects) object instead.
166168

169+
!!! tip "You can throw HTTP errors in your route handlers, middleware, or custom error handlers!"
170+
167171
=== "index.ts"
168172

169-
```ts hl_lines="3 10"
173+
```ts hl_lines="3 11"
170174
--8<-- "examples/snippets/event-handler/rest/gettingStarted_throwing_http_errors.ts:3"
171175
```
172176

@@ -194,15 +198,21 @@ All error classes accept optional parameters for custom messages and additional
194198

195199
### Route prefixes
196200

197-
!!! note "Coming soon"
198-
199201
When defining multiple routes related to a specific resource, it's common to have a shared prefix. For example, you might have several routes that all start with `/todos`.
200202

201203
For example, if you have a custom domain `api.example.com` and you want to map it to the `/v1` base path of your API. In this case, all the requests will contain `/v1/<resource>` in the path, requiring you to repeat the `/v1` prefix in all your route definitions.
202204

203-
At the moment, you have to manually include the prefix in each route definition, however we are planning to add support for route prefixes in a future release.
205+
To avoid repeating the prefix in each route definition, you can use the `prefix` constructor parameter when creating a new `Router` instance, and we'll automatically strip it from the request path before matching routes. After mapping a path prefix, the new root path will automatically be mapped to the path argument of `/`.
206+
207+
=== "index.ts"
208+
209+
```ts hl_lines="4 7"
210+
--8<-- "examples/snippets/event-handler/rest/gettingStarted_route_prefix.ts:3"
211+
```
204212

205-
Please [check this issue](https://github.com/aws-powertools/powertools-lambda-typescript/issues/4513) for more details and examples, and add 👍 if you would like us to prioritize it.
213+
This is also useful when splitting routes into separate files (see [Split routers](#split-routers) section) or when using [API mappings](https://docs.aws.amazon.com/apigateway/latest/developerguide/rest-api-mappings.html){target="_blank"} to map custom domains to specific base paths.
214+
215+
For example, when using `prefix: '/pay'`, there is no difference between a request path of `/pay` and `/pay/`; and the path argument would be defined as `/`.
206216

207217
## Advanced
208218

@@ -213,9 +223,8 @@ incoming request and your route handler. They provide a way to implement cross-c
213223
concerns like authentication, logging, validation, and response transformation without
214224
cluttering your route handlers.
215225

216-
Each middleware function receives the following arguments:
226+
Each middleware function receives two arguments:
217227

218-
* **params** - Route parameters extracted from the URL path
219228
* **reqCtx** - Request context containing the event, Lambda context, request, and response objects
220229
* **next** - A function to pass control to the next middleware in the chain
221230

@@ -312,6 +321,11 @@ that no post-processing of your request will occur.
312321
A common pattern to create reusable middleware is to implement a factory functions that
313322
accepts configuration options and returns a middleware function.
314323

324+
!!! note "Always `await next()` unless returning early"
325+
Middleware functions must always call `await next()` to pass control to the next middleware
326+
in the chain, unless you are intentionally returning early by returning a `Response` or
327+
JSON object.
328+
315329
=== "index.ts"
316330

317331
```ts hl_lines="20-21 36 41"

examples/snippets/event-handler/rest/advanced_compress.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const app = new Router();
88

99
app.use(compress());
1010

11-
app.get('/todos/:todoId', async ({ todoId }) => {
11+
app.get('/todos/:todoId', async ({ params: { todoId } }) => {
1212
const todo = await getTodoById(todoId);
1313
return { todo };
1414
});

examples/snippets/event-handler/rest/advanced_cors_per_route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ app.use(
1313
})
1414
);
1515

16-
app.get('/todos/:todoId', async ({ todoId }) => {
16+
app.get('/todos/:todoId', async ({ params: { todoId } }) => {
1717
const todo = await getTodoById(todoId);
1818
return { todo };
1919
});

examples/snippets/event-handler/rest/advanced_cors_simple.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ app.use(
1313
})
1414
);
1515

16-
app.get('/todos/:todoId', async ({ todoId }) => {
16+
app.get('/todos/:todoId', async ({ params: { todoId } }) => {
1717
const todo = await getTodoById(todoId);
1818
return { todo };
1919
});

examples/snippets/event-handler/rest/advanced_fine_grained_responses.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ app.get('/todos', async () => {
2323
});
2424
});
2525

26-
app.post('/todos', async (_, reqCtx) => {
27-
const body = await reqCtx.request.json();
26+
app.post('/todos', async ({ req }) => {
27+
const body = await req.json();
2828
const todo = await createTodo(body.title);
2929

3030
return new Response(JSON.stringify(todo), {

examples/snippets/event-handler/rest/advanced_mw_compose_middleware_index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ app.get('/todos', async () => {
1414
return { todos };
1515
});
1616

17-
app.post('/todos', async (_, { request }) => {
18-
const body = await request.json();
17+
app.post('/todos', async ({ req }) => {
18+
const body = await req.json();
1919
const todo = await putTodo(body);
2020
return todo;
2121
});

examples/snippets/event-handler/rest/advanced_mw_compose_middleware_shared.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ import { Logger } from '@aws-lambda-powertools/logger';
55

66
const logger = new Logger();
77

8-
const logging: Middleware = async (_, reqCtx, next) => {
9-
logger.info(`Request: ${reqCtx.request.method} ${reqCtx.request.url}`);
8+
const logging: Middleware = async ({ reqCtx, next }) => {
9+
logger.info(`Request: ${reqCtx.req.method} ${reqCtx.req.url}`);
1010
await next();
1111
logger.info(`Response: ${reqCtx.res.status}`);
1212
};
1313

14-
const rateLimit: Middleware = async (_, reqCtx, next) => {
14+
const rateLimit: Middleware = async ({ reqCtx, next }) => {
1515
// Rate limiting logic would go here
1616
reqCtx.res.headers.set('X-RateLimit-Limit', '100');
1717
await next();

examples/snippets/event-handler/rest/advanced_mw_custom_middleware.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ const store: { userId: string; roles: string[] } = { userId: '', roles: [] };
2525

2626
// Factory function that returns middleware
2727
const verifyToken = (options: { jwtSecret: string }): Middleware => {
28-
return async (_, { request }, next) => {
29-
const auth = request.headers.get('Authorization');
28+
return async ({ reqCtx: { req }, next }) => {
29+
const auth = req.headers.get('Authorization');
3030
if (!auth || !auth.startsWith('Bearer '))
31-
return new UnauthorizedError('Missing or invalid Authorization header');
31+
throw new UnauthorizedError('Missing or invalid Authorization header');
3232

3333
const token = auth.slice(7);
3434
try {
@@ -37,7 +37,7 @@ const verifyToken = (options: { jwtSecret: string }): Middleware => {
3737
store.roles = payload.roles;
3838
} catch (error) {
3939
logger.error('Token verification failed', { error });
40-
return new UnauthorizedError('Invalid token');
40+
throw new UnauthorizedError('Invalid token');
4141
}
4242

4343
await next();
@@ -47,7 +47,7 @@ const verifyToken = (options: { jwtSecret: string }): Middleware => {
4747
// Use custom middleware globally
4848
app.use(verifyToken({ jwtSecret }));
4949

50-
app.post('/todos', async (_) => {
50+
app.post('/todos', async () => {
5151
const { userId } = store;
5252
const todos = await getUserTodos(userId);
5353
return { todos };

examples/snippets/event-handler/rest/advanced_mw_destructuring_problem.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ import type { Context } from 'aws-lambda';
55
const app = new Router();
66

77
// ❌ WRONG: Using destructuring captures a reference to the original response
8-
const _badMiddleware: Middleware = async (_, { res }, next) => {
8+
const _badMiddleware: Middleware = async ({ reqCtx: { res }, next }) => {
99
res.headers.set('X-Before', 'Before');
1010
await next();
1111
// This header will NOT be added because 'res' is a stale reference
1212
res.headers.set('X-After', 'After');
1313
};
1414

1515
// ✅ CORRECT: Always access response through reqCtx
16-
const goodMiddleware: Middleware = async (_, reqCtx, next) => {
16+
const goodMiddleware: Middleware = async ({ reqCtx, next }) => {
1717
reqCtx.res.headers.set('X-Before', 'Before');
1818
await next();
1919
// This header WILL be added because we get the current response

examples/snippets/event-handler/rest/advanced_mw_early_return.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ const logger = new Logger();
99
const app = new Router({ logger });
1010

1111
// Authentication middleware - returns early if no auth header
12-
const authMiddleware: Middleware = async (_, reqCtx, next) => {
13-
const authHeader = reqCtx.request.headers.get('authorization');
12+
const authMiddleware: Middleware = async ({ reqCtx, next }) => {
13+
const authHeader = reqCtx.req.headers.get('authorization');
1414

1515
if (!authHeader) {
1616
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
@@ -23,7 +23,7 @@ const authMiddleware: Middleware = async (_, reqCtx, next) => {
2323
};
2424

2525
// Logging middleware - never executes when auth fails
26-
const loggingMiddleware: Middleware = async (_, __, next) => {
26+
const loggingMiddleware: Middleware = async ({ next }) => {
2727
logger.info('Request processed');
2828
await next();
2929
};

0 commit comments

Comments
 (0)