From 23c7ef0b6bd43dcb30e6c381290f4cea9427f1f6 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 24 Sep 2025 09:40:57 +0200 Subject: [PATCH 1/6] docs(event-handler): update API signatures --- .../event-handler/rest/advanced_compress.ts | 2 +- .../event-handler/rest/advanced_cors_per_route.ts | 2 +- .../event-handler/rest/advanced_cors_simple.ts | 2 +- .../rest/advanced_fine_grained_responses.ts | 4 ++-- .../rest/advanced_mw_compose_middleware_index.ts | 4 ++-- .../rest/advanced_mw_compose_middleware_shared.ts | 6 +++--- .../rest/advanced_mw_custom_middleware.ts | 10 +++++----- .../rest/advanced_mw_destructuring_problem.ts | 4 ++-- .../event-handler/rest/advanced_mw_early_return.ts | 6 +++--- .../rest/advanced_mw_middleware_order.ts | 13 ++++++------- .../rest/gettingStarted_dynamic_routes.ts | 2 +- .../rest/gettingStarted_error_handling.ts | 4 ++-- .../rest/gettingStarted_handle_not_found.ts | 2 +- .../event-handler/rest/gettingStarted_methods.ts | 4 ++-- .../rest/gettingStarted_multi_methods.ts | 4 ++-- .../rest/gettingStarted_serialization.ts | 5 ++--- .../rest/gettingStarted_throwing_http_errors.ts | 4 ++-- 17 files changed, 38 insertions(+), 40 deletions(-) diff --git a/examples/snippets/event-handler/rest/advanced_compress.ts b/examples/snippets/event-handler/rest/advanced_compress.ts index 44756a1e14..0a251a332f 100644 --- a/examples/snippets/event-handler/rest/advanced_compress.ts +++ b/examples/snippets/event-handler/rest/advanced_compress.ts @@ -8,7 +8,7 @@ const app = new Router(); app.use(compress()); -app.get('/todos/:todoId', async ({ todoId }) => { +app.get('/todos/:todoId', async ({ params: { todoId } }) => { const todo = await getTodoById(todoId); return { todo }; }); diff --git a/examples/snippets/event-handler/rest/advanced_cors_per_route.ts b/examples/snippets/event-handler/rest/advanced_cors_per_route.ts index 89a49f942f..feb080a381 100644 --- a/examples/snippets/event-handler/rest/advanced_cors_per_route.ts +++ b/examples/snippets/event-handler/rest/advanced_cors_per_route.ts @@ -13,7 +13,7 @@ app.use( }) ); -app.get('/todos/:todoId', async ({ todoId }) => { +app.get('/todos/:todoId', async ({ params: { todoId } }) => { const todo = await getTodoById(todoId); return { todo }; }); diff --git a/examples/snippets/event-handler/rest/advanced_cors_simple.ts b/examples/snippets/event-handler/rest/advanced_cors_simple.ts index b080185ce1..d86bef4356 100644 --- a/examples/snippets/event-handler/rest/advanced_cors_simple.ts +++ b/examples/snippets/event-handler/rest/advanced_cors_simple.ts @@ -13,7 +13,7 @@ app.use( }) ); -app.get('/todos/:todoId', async ({ todoId }) => { +app.get('/todos/:todoId', async ({ params: { todoId } }) => { const todo = await getTodoById(todoId); return { todo }; }); diff --git a/examples/snippets/event-handler/rest/advanced_fine_grained_responses.ts b/examples/snippets/event-handler/rest/advanced_fine_grained_responses.ts index 26cd5d204c..eb918c8587 100644 --- a/examples/snippets/event-handler/rest/advanced_fine_grained_responses.ts +++ b/examples/snippets/event-handler/rest/advanced_fine_grained_responses.ts @@ -23,8 +23,8 @@ app.get('/todos', async () => { }); }); -app.post('/todos', async (_, reqCtx) => { - const body = await reqCtx.request.json(); +app.post('/todos', async ({ req }) => { + const body = await req.json(); const todo = await createTodo(body.title); return new Response(JSON.stringify(todo), { diff --git a/examples/snippets/event-handler/rest/advanced_mw_compose_middleware_index.ts b/examples/snippets/event-handler/rest/advanced_mw_compose_middleware_index.ts index e1a26356b3..5b6e9c2499 100644 --- a/examples/snippets/event-handler/rest/advanced_mw_compose_middleware_index.ts +++ b/examples/snippets/event-handler/rest/advanced_mw_compose_middleware_index.ts @@ -14,8 +14,8 @@ app.get('/todos', async () => { return { todos }; }); -app.post('/todos', async (_, { request }) => { - const body = await request.json(); +app.post('/todos', async ({ req }) => { + const body = await req.json(); const todo = await putTodo(body); return todo; }); diff --git a/examples/snippets/event-handler/rest/advanced_mw_compose_middleware_shared.ts b/examples/snippets/event-handler/rest/advanced_mw_compose_middleware_shared.ts index 1a475aa13b..190d5365f0 100644 --- a/examples/snippets/event-handler/rest/advanced_mw_compose_middleware_shared.ts +++ b/examples/snippets/event-handler/rest/advanced_mw_compose_middleware_shared.ts @@ -5,13 +5,13 @@ import { Logger } from '@aws-lambda-powertools/logger'; const logger = new Logger(); -const logging: Middleware = async (_, reqCtx, next) => { - logger.info(`Request: ${reqCtx.request.method} ${reqCtx.request.url}`); +const logging: Middleware = async ({ reqCtx, next }) => { + logger.info(`Request: ${reqCtx.req.method} ${reqCtx.req.url}`); await next(); logger.info(`Response: ${reqCtx.res.status}`); }; -const rateLimit: Middleware = async (_, reqCtx, next) => { +const rateLimit: Middleware = async ({ reqCtx, next }) => { // Rate limiting logic would go here reqCtx.res.headers.set('X-RateLimit-Limit', '100'); await next(); diff --git a/examples/snippets/event-handler/rest/advanced_mw_custom_middleware.ts b/examples/snippets/event-handler/rest/advanced_mw_custom_middleware.ts index 05f560c325..8e852dd523 100644 --- a/examples/snippets/event-handler/rest/advanced_mw_custom_middleware.ts +++ b/examples/snippets/event-handler/rest/advanced_mw_custom_middleware.ts @@ -25,10 +25,10 @@ const store: { userId: string; roles: string[] } = { userId: '', roles: [] }; // Factory function that returns middleware const verifyToken = (options: { jwtSecret: string }): Middleware => { - return async (_, { request }, next) => { - const auth = request.headers.get('Authorization'); + return async ({ reqCtx: { req }, next }) => { + const auth = req.headers.get('Authorization'); if (!auth || !auth.startsWith('Bearer ')) - return new UnauthorizedError('Missing or invalid Authorization header'); + throw new UnauthorizedError('Missing or invalid Authorization header'); const token = auth.slice(7); try { @@ -37,7 +37,7 @@ const verifyToken = (options: { jwtSecret: string }): Middleware => { store.roles = payload.roles; } catch (error) { logger.error('Token verification failed', { error }); - return new UnauthorizedError('Invalid token'); + throw new UnauthorizedError('Invalid token'); } await next(); @@ -47,7 +47,7 @@ const verifyToken = (options: { jwtSecret: string }): Middleware => { // Use custom middleware globally app.use(verifyToken({ jwtSecret })); -app.post('/todos', async (_) => { +app.post('/todos', async () => { const { userId } = store; const todos = await getUserTodos(userId); return { todos }; diff --git a/examples/snippets/event-handler/rest/advanced_mw_destructuring_problem.ts b/examples/snippets/event-handler/rest/advanced_mw_destructuring_problem.ts index eaaca2bc2b..b1fd622248 100644 --- a/examples/snippets/event-handler/rest/advanced_mw_destructuring_problem.ts +++ b/examples/snippets/event-handler/rest/advanced_mw_destructuring_problem.ts @@ -5,7 +5,7 @@ import type { Context } from 'aws-lambda'; const app = new Router(); // ❌ WRONG: Using destructuring captures a reference to the original response -const _badMiddleware: Middleware = async (_, { res }, next) => { +const _badMiddleware: Middleware = async ({ reqCtx: { res }, next }) => { res.headers.set('X-Before', 'Before'); await next(); // This header will NOT be added because 'res' is a stale reference @@ -13,7 +13,7 @@ const _badMiddleware: Middleware = async (_, { res }, next) => { }; // ✅ CORRECT: Always access response through reqCtx -const goodMiddleware: Middleware = async (_, reqCtx, next) => { +const goodMiddleware: Middleware = async ({ reqCtx, next }) => { reqCtx.res.headers.set('X-Before', 'Before'); await next(); // This header WILL be added because we get the current response diff --git a/examples/snippets/event-handler/rest/advanced_mw_early_return.ts b/examples/snippets/event-handler/rest/advanced_mw_early_return.ts index 4a1d26df9e..e973269e67 100644 --- a/examples/snippets/event-handler/rest/advanced_mw_early_return.ts +++ b/examples/snippets/event-handler/rest/advanced_mw_early_return.ts @@ -9,8 +9,8 @@ const logger = new Logger(); const app = new Router({ logger }); // Authentication middleware - returns early if no auth header -const authMiddleware: Middleware = async (_, reqCtx, next) => { - const authHeader = reqCtx.request.headers.get('authorization'); +const authMiddleware: Middleware = async ({ reqCtx, next }) => { + const authHeader = reqCtx.req.headers.get('authorization'); if (!authHeader) { return new Response(JSON.stringify({ error: 'Unauthorized' }), { @@ -23,7 +23,7 @@ const authMiddleware: Middleware = async (_, reqCtx, next) => { }; // Logging middleware - never executes when auth fails -const loggingMiddleware: Middleware = async (_, __, next) => { +const loggingMiddleware: Middleware = async ({ next }) => { logger.info('Request processed'); await next(); }; diff --git a/examples/snippets/event-handler/rest/advanced_mw_middleware_order.ts b/examples/snippets/event-handler/rest/advanced_mw_middleware_order.ts index fc86013b5e..418e3f4142 100644 --- a/examples/snippets/event-handler/rest/advanced_mw_middleware_order.ts +++ b/examples/snippets/event-handler/rest/advanced_mw_middleware_order.ts @@ -10,14 +10,14 @@ const logger = new Logger(); const app = new Router({ logger }); // Global middleware - executes first in pre-processing, last in post-processing -app.use(async (_, reqCtx, next) => { +app.use(async ({ reqCtx, next }) => { reqCtx.res.headers.set('x-pre-processed-by', 'global-middleware'); await next(); reqCtx.res.headers.set('x-post-processed-by', 'global-middleware'); }); // Route-specific middleware - executes second in pre-processing, first in post-processing -const routeMiddleware: Middleware = async (_, reqCtx, next) => { +const routeMiddleware: Middleware = async ({ reqCtx, next }) => { reqCtx.res.headers.set('x-pre-processed-by', 'route-middleware'); await next(); reqCtx.res.headers.set('x-post-processed-by', 'route-middleware'); @@ -31,12 +31,11 @@ app.get('/todos', async () => { // This route will have: // x-pre-processed-by: route-middleware (route middleware overwrites global) // x-post-processed-by: global-middleware (global middleware executes last) -app.post('/todos', [routeMiddleware], async (_, reqCtx) => { - const body = await reqCtx.request.json(); +app.post('/todos', [routeMiddleware], async ({ req }) => { + const body = await req.json(); const todo = await putTodo(body); return todo; }); -export const handler = async (event: unknown, context: Context) => { - return app.resolve(event, context); -}; +export const handler = async (event: unknown, context: Context) => + app.resolve(event, context); diff --git a/examples/snippets/event-handler/rest/gettingStarted_dynamic_routes.ts b/examples/snippets/event-handler/rest/gettingStarted_dynamic_routes.ts index 426588ebe9..4f9f0fd0fb 100644 --- a/examples/snippets/event-handler/rest/gettingStarted_dynamic_routes.ts +++ b/examples/snippets/event-handler/rest/gettingStarted_dynamic_routes.ts @@ -13,7 +13,7 @@ const logger = new Logger({ }); const app = new Router({ logger }); -app.get('/todos/:todoId', async ({ todoId }) => { +app.get('/todos/:todoId', async ({ params: { todoId } }) => { const todo = await getTodoById(todoId); return { todo }; }); diff --git a/examples/snippets/event-handler/rest/gettingStarted_error_handling.ts b/examples/snippets/event-handler/rest/gettingStarted_error_handling.ts index 9465fa6d02..850ea93db0 100644 --- a/examples/snippets/event-handler/rest/gettingStarted_error_handling.ts +++ b/examples/snippets/event-handler/rest/gettingStarted_error_handling.ts @@ -16,12 +16,12 @@ app.errorHandler(GetTodoError, async (error, reqCtx) => { return { statusCode: HttpErrorCodes.BAD_REQUEST, - message: `Bad request: ${error.message} - ${reqCtx.request.headers.get('x-correlation-id')}`, + message: `Bad request: ${error.message} - ${reqCtx.req.headers.get('x-correlation-id')}`, error: 'BadRequest', }; }); -app.get('/todos/:todoId', async ({ todoId }) => { +app.get('/todos/:todoId', async ({ params: { todoId } }) => { const todo = await getTodoById(todoId); // May throw GetTodoError return { todo }; }); diff --git a/examples/snippets/event-handler/rest/gettingStarted_handle_not_found.ts b/examples/snippets/event-handler/rest/gettingStarted_handle_not_found.ts index 970fc7b294..e6271edc7b 100644 --- a/examples/snippets/event-handler/rest/gettingStarted_handle_not_found.ts +++ b/examples/snippets/event-handler/rest/gettingStarted_handle_not_found.ts @@ -15,7 +15,7 @@ app.notFound(async (error, reqCtx) => { statusCode: HttpErrorCodes.IM_A_TEAPOT, body: "I'm a teapot!", headers: { - 'x-correlation-id': reqCtx.request.headers.get('x-correlation-id'), + 'x-correlation-id': reqCtx.req.headers.get('x-correlation-id'), }, }; }); diff --git a/examples/snippets/event-handler/rest/gettingStarted_methods.ts b/examples/snippets/event-handler/rest/gettingStarted_methods.ts index f63ffe306a..0a345dbb3a 100644 --- a/examples/snippets/event-handler/rest/gettingStarted_methods.ts +++ b/examples/snippets/event-handler/rest/gettingStarted_methods.ts @@ -13,8 +13,8 @@ const logger = new Logger({ }); const app = new Router({ logger }); -app.post('/todos', async (_, { request }) => { - const body = await request.json(); +app.post('/todos', async ({ req }) => { + const body = await req.json(); const todo = await putTodo(body); return todo; diff --git a/examples/snippets/event-handler/rest/gettingStarted_multi_methods.ts b/examples/snippets/event-handler/rest/gettingStarted_multi_methods.ts index 4888d31097..3d1e9109ec 100644 --- a/examples/snippets/event-handler/rest/gettingStarted_multi_methods.ts +++ b/examples/snippets/event-handler/rest/gettingStarted_multi_methods.ts @@ -14,8 +14,8 @@ const logger = new Logger({ const app = new Router({ logger }); app.route( - async (_, { request }) => { - const body = await request.json(); + async ({ req }) => { + const body = await req.json(); const todo = await putTodo(body); return todo; diff --git a/examples/snippets/event-handler/rest/gettingStarted_serialization.ts b/examples/snippets/event-handler/rest/gettingStarted_serialization.ts index 5b93f14004..7bbc22f305 100644 --- a/examples/snippets/event-handler/rest/gettingStarted_serialization.ts +++ b/examples/snippets/event-handler/rest/gettingStarted_serialization.ts @@ -7,6 +7,5 @@ app.get('/ping', async () => { return { message: 'pong' }; // (1)! }); -export const handler = async (event: unknown, context: Context) => { - return app.resolve(event, context); -}; +export const handler = async (event: unknown, context: Context) => + app.resolve(event, context); diff --git a/examples/snippets/event-handler/rest/gettingStarted_throwing_http_errors.ts b/examples/snippets/event-handler/rest/gettingStarted_throwing_http_errors.ts index 417a9a2e8b..5950720d77 100644 --- a/examples/snippets/event-handler/rest/gettingStarted_throwing_http_errors.ts +++ b/examples/snippets/event-handler/rest/gettingStarted_throwing_http_errors.ts @@ -8,8 +8,8 @@ import type { Context } from 'aws-lambda'; const app = new Router(); -app.use(async (_, reqCtx, next) => { - if (!isAuthenticated(reqCtx.request.headers.get('Authorization') ?? '')) { +app.use(async ({ reqCtx, next }) => { + if (!isAuthenticated(reqCtx.req.headers.get('Authorization') ?? '')) { throw new UnauthorizedError(); // This will return a 401 Unauthorized response } await next(); From 915ae64eddef43c55aa5371dfcbb95307b5aab9a Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 24 Sep 2025 09:49:59 +0200 Subject: [PATCH 2/6] docs: add route prefixes section --- docs/features/event-handler/rest.md | 14 ++++++++++---- .../rest/gettingStarted_rute_prefix.ts | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 examples/snippets/event-handler/rest/gettingStarted_rute_prefix.ts diff --git a/docs/features/event-handler/rest.md b/docs/features/event-handler/rest.md index 18ec89cad4..3991d88f79 100644 --- a/docs/features/event-handler/rest.md +++ b/docs/features/event-handler/rest.md @@ -194,15 +194,21 @@ All error classes accept optional parameters for custom messages and additional ### Route prefixes -!!! note "Coming soon" - 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`. 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/` in the path, requiring you to repeat the `/v1` prefix in all your route definitions. -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. +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 `/`. + +=== "index.ts" + + ```ts hl_lines="6 9" + --8<-- "examples/snippets/event-handler/rest/gettingStarted_route_prefix.ts:3" + ``` + +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. -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. +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 `/`. ## Advanced diff --git a/examples/snippets/event-handler/rest/gettingStarted_rute_prefix.ts b/examples/snippets/event-handler/rest/gettingStarted_rute_prefix.ts new file mode 100644 index 0000000000..3a0ca18f6d --- /dev/null +++ b/examples/snippets/event-handler/rest/gettingStarted_rute_prefix.ts @@ -0,0 +1,15 @@ +declare function getUserTodos(auth: string | null): Promise<{ id: string }>; + +import { Router } from '@aws-lambda-powertools/event-handler/experimental-rest'; +import type { Context } from 'aws-lambda'; + +const app = new Router({ prefix: '/todos' }); + +// matches POST /todos +app.post('/', async ({ req: { headers } }) => { + const todos = await getUserTodos(headers.get('Authorization')); + return { todos }; +}); + +export const handler = async (event: unknown, context: Context) => + app.resolve(event, context); From 599ec43197948a808e014c570183a2d1b7b610e8 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 24 Sep 2025 10:06:54 +0200 Subject: [PATCH 3/6] chore: fix file name --- .../rest/gettingStarted_route_prefix.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 examples/snippets/event-handler/rest/gettingStarted_route_prefix.ts diff --git a/examples/snippets/event-handler/rest/gettingStarted_route_prefix.ts b/examples/snippets/event-handler/rest/gettingStarted_route_prefix.ts new file mode 100644 index 0000000000..3a0ca18f6d --- /dev/null +++ b/examples/snippets/event-handler/rest/gettingStarted_route_prefix.ts @@ -0,0 +1,15 @@ +declare function getUserTodos(auth: string | null): Promise<{ id: string }>; + +import { Router } from '@aws-lambda-powertools/event-handler/experimental-rest'; +import type { Context } from 'aws-lambda'; + +const app = new Router({ prefix: '/todos' }); + +// matches POST /todos +app.post('/', async ({ req: { headers } }) => { + const todos = await getUserTodos(headers.get('Authorization')); + return { todos }; +}); + +export const handler = async (event: unknown, context: Context) => + app.resolve(event, context); From e0ad0a4072bd02dba6862b764388bbdb1ceba374 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 24 Sep 2025 10:07:17 +0200 Subject: [PATCH 4/6] docs: additional clarifications --- docs/features/event-handler/rest.md | 15 ++++++++++++--- .../rest/gettingStarted_error_handling.ts | 1 - .../rest/gettingStarted_rute_prefix.ts | 15 --------------- 3 files changed, 12 insertions(+), 19 deletions(-) delete mode 100644 examples/snippets/event-handler/rest/gettingStarted_rute_prefix.ts diff --git a/docs/features/event-handler/rest.md b/docs/features/event-handler/rest.md index 3991d88f79..ac73673ea5 100644 --- a/docs/features/event-handler/rest.md +++ b/docs/features/event-handler/rest.md @@ -148,6 +148,8 @@ You can use the `errorHandler()` method as a higher-order function or class meth This allows you to catch and return custom error responses, or perform any other error handling logic you need. +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. + !!! tip "You can also pass a list of error classes to the `errorHandler()` method." === "index.ts" @@ -158,15 +160,17 @@ This allows you to catch and return custom error responses, or perform any other ### Throwing HTTP errors -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. +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. This ensures that your Lambda function doesn't fail but returns a well-defined HTTP error response to the client. If you need to send custom headers or a different response structure/code, you can use the [Response](#returning-response-objects) object instead. +!!! tip "You can throw HTTP errors in your route handlers, middleware, or custom error handlers!" + === "index.ts" - ```ts hl_lines="3 10" + ```ts hl_lines="3 11" --8<-- "examples/snippets/event-handler/rest/gettingStarted_throwing_http_errors.ts:3" ``` @@ -202,7 +206,7 @@ To avoid repeating the prefix in each route definition, you can use the `prefix` === "index.ts" - ```ts hl_lines="6 9" + ```ts hl_lines="4 7" --8<-- "examples/snippets/event-handler/rest/gettingStarted_route_prefix.ts:3" ``` @@ -318,6 +322,11 @@ that no post-processing of your request will occur. A common pattern to create reusable middleware is to implement a factory functions that accepts configuration options and returns a middleware function. +!!! note "Always `await next()` unless returning early" + Middleware functions must always call `await next()` to pass control to the next middleware + in the chain, unless you are intentionally returning early by returning a `Response` or + JSON object. + === "index.ts" ```ts hl_lines="20-21 36 41" diff --git a/examples/snippets/event-handler/rest/gettingStarted_error_handling.ts b/examples/snippets/event-handler/rest/gettingStarted_error_handling.ts index 850ea93db0..dede09cb21 100644 --- a/examples/snippets/event-handler/rest/gettingStarted_error_handling.ts +++ b/examples/snippets/event-handler/rest/gettingStarted_error_handling.ts @@ -17,7 +17,6 @@ app.errorHandler(GetTodoError, async (error, reqCtx) => { return { statusCode: HttpErrorCodes.BAD_REQUEST, message: `Bad request: ${error.message} - ${reqCtx.req.headers.get('x-correlation-id')}`, - error: 'BadRequest', }; }); diff --git a/examples/snippets/event-handler/rest/gettingStarted_rute_prefix.ts b/examples/snippets/event-handler/rest/gettingStarted_rute_prefix.ts deleted file mode 100644 index 3a0ca18f6d..0000000000 --- a/examples/snippets/event-handler/rest/gettingStarted_rute_prefix.ts +++ /dev/null @@ -1,15 +0,0 @@ -declare function getUserTodos(auth: string | null): Promise<{ id: string }>; - -import { Router } from '@aws-lambda-powertools/event-handler/experimental-rest'; -import type { Context } from 'aws-lambda'; - -const app = new Router({ prefix: '/todos' }); - -// matches POST /todos -app.post('/', async ({ req: { headers } }) => { - const todos = await getUserTodos(headers.get('Authorization')); - return { todos }; -}); - -export const handler = async (event: unknown, context: Context) => - app.resolve(event, context); From 6e805c9049c2291fbfed13d275cebd1592af53f0 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 24 Sep 2025 10:45:46 +0200 Subject: [PATCH 5/6] chore: fix diagrams --- docs/features/event-handler/rest.md | 3 +-- .../rest/diagrams/middleware_early_return.mermaid | 4 ++-- .../rest/diagrams/middleware_error_handling.mermaid | 4 ++-- .../rest/diagrams/middleware_execution_order.mermaid | 6 +++--- .../rest/diagrams/middleware_handled_error.mermaid | 6 +++--- .../rest/diagrams/middleware_throwing_error.mermaid | 4 ++-- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/docs/features/event-handler/rest.md b/docs/features/event-handler/rest.md index ac73673ea5..3df38ecc41 100644 --- a/docs/features/event-handler/rest.md +++ b/docs/features/event-handler/rest.md @@ -223,9 +223,8 @@ incoming request and your route handler. They provide a way to implement cross-c concerns like authentication, logging, validation, and response transformation without cluttering your route handlers. -Each middleware function receives the following arguments: +Each middleware function receives two arguments: -* **params** - Route parameters extracted from the URL path * **reqCtx** - Request context containing the event, Lambda context, request, and response objects * **next** - A function to pass control to the next middleware in the chain diff --git a/examples/snippets/event-handler/rest/diagrams/middleware_early_return.mermaid b/examples/snippets/event-handler/rest/diagrams/middleware_early_return.mermaid index ca7e189db5..6a54e217ba 100644 --- a/examples/snippets/event-handler/rest/diagrams/middleware_early_return.mermaid +++ b/examples/snippets/event-handler/rest/diagrams/middleware_early_return.mermaid @@ -7,9 +7,9 @@ sequenceDiagram participant Handler as Route Handler Request->>Router: Incoming Request - Router->>M1: Execute (params, reqCtx, next) + Router->>M1: Execute ({ reqCtx, next }) Note over M1: Pre-processing - M1->>M2: Call next() + M1->>M2: Call await next() Note over M2: Pre-processing M2->>M2: Return Response (early return) Note over M2: Post-processing diff --git a/examples/snippets/event-handler/rest/diagrams/middleware_error_handling.mermaid b/examples/snippets/event-handler/rest/diagrams/middleware_error_handling.mermaid index 5c5aafa569..cae7119608 100644 --- a/examples/snippets/event-handler/rest/diagrams/middleware_error_handling.mermaid +++ b/examples/snippets/event-handler/rest/diagrams/middleware_error_handling.mermaid @@ -7,9 +7,9 @@ sequenceDiagram participant Handler as Route Handler Request->>Router: Incoming Request - Router->>M1: Execute (params, reqCtx, next) + Router->>M1: Execute ({ reqCtx, next }) Note over M1: Pre-processing - M1->>M2: Call next() + M1->>M2: Call await next() Note over M2: Throws Error M2-->>M1: Error propagated M1-->>Router: Error propagated diff --git a/examples/snippets/event-handler/rest/diagrams/middleware_execution_order.mermaid b/examples/snippets/event-handler/rest/diagrams/middleware_execution_order.mermaid index 696be1264d..b8befe4d20 100644 --- a/examples/snippets/event-handler/rest/diagrams/middleware_execution_order.mermaid +++ b/examples/snippets/event-handler/rest/diagrams/middleware_execution_order.mermaid @@ -6,11 +6,11 @@ sequenceDiagram participant Handler as Route Handler Request->>Router: Incoming Request - Router->>GM: Execute (params, reqCtx, next) + Router->>GM: Execute ({ reqCtx, next }) Note over GM: Pre-processing - GM->>RM: Call next() + GM->>RM: Call await next() Note over RM: Pre-processing - RM->>Handler: Call next() + RM->>Handler: Call await next() Note over Handler: Execute handler Handler-->>RM: Return Note over RM: Post-processing diff --git a/examples/snippets/event-handler/rest/diagrams/middleware_handled_error.mermaid b/examples/snippets/event-handler/rest/diagrams/middleware_handled_error.mermaid index 5d0da29a88..395983fda4 100644 --- a/examples/snippets/event-handler/rest/diagrams/middleware_handled_error.mermaid +++ b/examples/snippets/event-handler/rest/diagrams/middleware_handled_error.mermaid @@ -6,12 +6,12 @@ sequenceDiagram participant Handler as Route Handler Request->>Router: Incoming Request - Router->>M1: Execute (params, reqCtx, next) + Router->>M1: Execute ({ reqCtx, next }) Note over M1: Pre-processing - M1->>M2: Call next() + M1->>M2: Call await next() Note over M2: Error thrown & caught Note over M2: Handle error gracefully - M2->>Handler: Call next() + M2->>Handler: Call await next() Note over Handler: Execute handler Handler-->>M2: Return Note over M2: Post-processing diff --git a/examples/snippets/event-handler/rest/diagrams/middleware_throwing_error.mermaid b/examples/snippets/event-handler/rest/diagrams/middleware_throwing_error.mermaid index 25ed59d74d..6a57cccd23 100644 --- a/examples/snippets/event-handler/rest/diagrams/middleware_throwing_error.mermaid +++ b/examples/snippets/event-handler/rest/diagrams/middleware_throwing_error.mermaid @@ -7,9 +7,9 @@ sequenceDiagram participant Handler as Route Handler Request->>Router: Incoming Request - Router->>M1: Execute (params, reqCtx, next) + Router->>M1: Execute ({ reqCtx, next }) Note over M1: Pre-processing - M1->>M2: Call next() + M1->>M2: Call await next() Note over M2: Intentionally throws error M2-->>M1: Error propagated M1-->>Router: Error propagated From 31d33f46d3172e82dabc729e6fe71ef300ebad74 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 24 Sep 2025 10:46:27 +0200 Subject: [PATCH 6/6] chore: fix req --- docs/features/event-handler/rest.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/event-handler/rest.md b/docs/features/event-handler/rest.md index 3df38ecc41..136565eb2f 100644 --- a/docs/features/event-handler/rest.md +++ b/docs/features/event-handler/rest.md @@ -128,7 +128,7 @@ Please [check this issue](https://github.com/aws-powertools/powertools-lambda-ty ### Accessing request details -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`. +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`. ### Handling not found routes