Summary
We're excited to announce an update to our Event Handler utility, featuring new middleware for CORS (Cross-Origin Resource Sharing) configuration and automatic response compression. We have also added support for Route Prefixes which allows you to avoid repeating a shared prefix in each route definition.
We've listened to your feedback and also made some slight changes to the type signature in the handlers to improve developer experience.
We have also made the error handlers more versatile by allowing a Response object or a JavaScript object to be returned from the error handler.
⭐ Congratulations @guillemcomerma for their first PR merged in the project, and thank you to @shrivarshapoojari and @dani-abib for their contributions 🎉
CORS Middleware
The CORS middleware ensures CORS headers are returned as part of the response when your functions match the path invoked and the Origin matches one of the allowed values.
import { Router } from '@aws-lambda-powertools/event-handler/experimental-rest';
import { cors } from '@aws-lambda-powertools/event-handler/experimental-rest/middleware';
import type { Context } from 'aws-lambda';
const app = new Router();
app.use(
cors({
origin: 'https://example.com',
maxAge: 300,
})
);
app.get('/todos/:todoId', async ({ params: { todoId } }) => {
const todo = await getTodoById(todoId);
return { todo };
});
export const handler = async (event: unknown, context: Context) =>
app.resolve(event, context);
/**
When invoked from a valid origin, this returns:
{
"statusCode": 200,
"headers": {
"access-control-allow-credentials": "false",
"access-control-allow-origin": "https://example.com",
"content-type": "application/json"
},
"multiValueHeaders": {
"access-control-allow-headers": [
"Authorization",
"Content-Type",
"X-Amz-Date",
"X-Api-Key",
"X-Amz-Security-Token"
],
"access-control-allow-methods": [
"DELETE",
"GET",
"HEAD",
"PATCH",
"POST",
"PUT"
]
},
"body": "{\"todoId\":\"123\",\"task\":\"Example task\",\"completed\":false}",
"isBase64Encoded": false
}
**/
Compress Middleware
The compress middleware automatically compresses responses using gzip and base64 encodes them when the client indicates support via the Accept-Encoding header.
import { Router } from '@aws-lambda-powertools/event-handler/experimental-rest';
import { compress } from '@aws-lambda-powertools/event-handler/experimental-rest/middleware';
import type { Context } from 'aws-lambda';
const app = new Router();
app.use(compress());
app.get('/todos/:todoId', async ({ params: { todoId } }) => {
const todo = await getTodoById(todoId);
return { todo };
});
export const handler = async (event: unknown, context: Context) =>
app.resolve(event, context);
/**
When invoked with the following request,
{
"headers": {
"Accept-Encoding": "gzip"
},
"resource": "/todos/1",
"path": "/todos/1",
"httpMethod": "GET"
}
it would return,
{
"statusCode": 200,
"multiValueHeaders": {
"Content-Type": [
"application/json"
],
"Content-Encoding": [
"gzip"
]
},
"body": "H4sIAAAAAAACE42STU4DMQyFrxJl3QXln96AMyAW7sSDLCVxiJ0Kqerd8TCCUOgii1EmP/783pOPXjmw+N3L0TfB+hz8brvxtC5KGtHvfMCIkzZx0HT5MPmNnziViIr2dIYoeNr8Q1x3xHsjcVadIbkZJoq2RXU8zzQROLseQ9505NzeCNQdMJNBE+UmY4zbzjAJhWtlZ57sB84BWtul+rteH2HPlVgWARwjqXkxpklK5gmEHAQqJBMtFsGVygcKmNVRjG0wxvuzGF2L0dpVUOKMC3bfJNjJgWMrCuZk7cUp02AiD72D6WKHHwUDKbiJs6AZ0VZXKOUx4uNvzdxT+E4mLcMA+6G8nzrLQkaxkNEVrFKW2VGbJCoCY7q2V3+tiv5kGThyxfTecDWbgGz/NfYXhL6ePgF9PnFdPgMAAA==",
"isBase64Encoded": true
}
**/
Route Prefixes
When defining multiple routes related to a specific resource, 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. This will prevent you to avoid repeating the prefix in each route definition.
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);
Type Signature Changes
We’ve also made changes to some type signatures to reduce parameter complexity.
The path parameters in the route handlers have been moved to reqCtx
app.get('/todos/:todoId', async (reqCtx) => {
return { id: reqCtx.params.todoId };
});
Previously middleware used positional arguments:
const middleware: Middleware = async (params, reqCtx, next) => {
logger.info('Request processed');
await next();
};
Now, we have changed it to be an object so customers can pick only the parameters that they want and also moved the params
parameter to reqCtx
const middleware: Middleware = async ({ reqCtx: { params }, next }) => {
logger.info('Request processed');
await next();
};
We have also changed the request
property to req
in the RequestContext
type to maintain consistency with the res property.
Improvements on Error Handling
Error handlers can now return a Response object or a JavaScript object that will be auto-serialized.
import {
HttpStatusCodes,
Router,
} from '@aws-lambda-powertools/event-handler/experimental-rest';
import { Logger } from '@aws-lambda-powertools/logger';
import type { Context } from 'aws-lambda/handler';
const logger = new Logger();
const app = new Router({ logger });
app.errorHandler(GetTodoError, async (error, reqCtx) => {
logger.error('Unable to get todo', { error });
return {
statusCode: HttpStatusCodes.BAD_REQUEST,
message: `Bad request: ${error.message} - ${reqCtx.req.headers.get('x-correlation-id')}`,
};
});
app.get('/todos/:todoId', async ({ params: { todoId } }) => {
const todo = await getTodoById(todoId); // May throw GetTodoError
return { todo };
});
export const handler = async (event: unknown, context: Context) =>
app.resolve(event, context);
Changes
- chore: sanitize CI inputs via env var (#4528) by @dreamorosi
- improv(event-handler): rename HttpErrorCodes to HttpStatusCodes (#4543) by @dreamorosi
- docs(idempotency): fix dataKeywordArgument reference and remove unused test code (#4537) by @guillemcomerma
- improv(event-handler): made error handler responses versatile (#4536) by @sdangol
- chore(ci): add
registry-url
tosetup-node
steps to fix Scorecard packaging check (#4539) by @shrivarshapoojari - improv(event-handler): changed path parameter in middleware and routehandler signature (#4532) by @sdangol
- improv(event-handler): changed the Middleware and RequestContext signatures (#4530) by @sdangol
- fix(event-handler): fixed CORS behaviour not aligned with CORS spec (#4512) by @sdangol
- feat(event-handler): implemented route prefixes in HTTP event handler (#4523) by @sdangol
- feat(event-handler): throw error when middleware does not await next() (#4511) by @svozza
- chore: always append
PTEnv
to UA string (#4522) by @dreamorosi - fix(event-handler): run global middleware on all requests for REST API (#4507) by @svozza
- fix(batch): fixed the build issue with Batch processor due to missing dependencies (#4498) by @sdangol
- feat(event-handler): added compress middleware for the REST API event handler (#4495) by @sdangol
- feat(event-handler): add CORS middleware support (#4477) by @dcabib
📜 Documentation updates
- chore(ci): update layer ARN on documentation (#4535) by @sdangol
- docs(event-handler): update to new APIs before release (#4542) by @dreamorosi
- chore(deps): bump the aws-cdk group across 1 directory with 3 updates (#4527) by @dependabot[bot]
- chore(deps): bump the aws-sdk-v3 group across 1 directory with 62 updates (#4526) by @dependabot[bot]
- docs(event-handler): general improvements (#4517) by @dreamorosi
- chore(deps): bump esbuild from 0.25.9 to 0.25.10 (#4503) by @dependabot[bot]
- chore(deps): bump @types/node from 24.5.1 to 24.5.2 (#4505) by @dependabot[bot]
- chore(deps): bump mkdocs-llmstxt from 0.3.1 to 0.3.2 in /docs (#4508) by @dependabot[bot]
- chore(deps): bump @types/node from 24.5.0 to 24.5.1 (#4501) by @dependabot[bot]
- fix(batch): fixed the build issue with Batch processor due to missing dependencies (#4498) by @sdangol
- chore(deps): bump the aws-sdk-v3 group across 1 directory with 88 updates (#4494) by @dependabot[bot]
- chore(deps): bump @types/node from 24.4.0 to 24.5.0 (#4497) by @dependabot[bot]
- chore(deps): bump @types/node from 24.3.1 to 24.4.0 (#4493) by @dependabot[bot]
- chore(deps): bump mkdocs-material from 9.6.19 to 9.6.20 in /docs (#4492) by @dependabot[bot]
- chore(deps): bump squidfunk/mkdocs-material from
209b62d
to86d21da
in /docs (#4490) by @dependabot[bot] - chore(ci): update layer ARN on documentation (#4488) by @sdangol
🔧 Maintenance
- chore(deps): bump the aws-cdk group across 1 directory with 3 updates (#4527) by @dependabot[bot]
- chore(deps): bump the aws-sdk-v3 group across 1 directory with 62 updates (#4526) by @dependabot[bot]
- chore(deps-dev): bump lint-staged from 16.1.6 to 16.2.0 (#4525) by @dependabot[bot]
- chore(deps-dev): bump zod from 4.1.9 to 4.1.11 (#4524) by @dependabot[bot]
- chore(deps-dev): bump @valkey/valkey-glide from 2.0.1 to 2.1.0 (#4504) by @dependabot[bot]
- chore(deps): bump esbuild from 0.25.9 to 0.25.10 (#4503) by @dependabot[bot]
- chore(deps): bump @types/node from 24.5.1 to 24.5.2 (#4505) by @dependabot[bot]
- chore(deps): bump mkdocs-llmstxt from 0.3.1 to 0.3.2 in /docs (#4508) by @dependabot[bot]
- chore(deps): bump @types/node from 24.5.0 to 24.5.1 (#4501) by @dependabot[bot]
- chore(deps-dev): bump zod from 4.1.8 to 4.1.9 (#4500) by @dependabot[bot]
- chore(deps): bump the aws-sdk-v3 group across 1 directory with 88 updates (#4494) by @dependabot[bot]
- chore(deps): bump @types/node from 24.4.0 to 24.5.0 (#4497) by @dependabot[bot]
- chore(deps): bump @types/node from 24.3.1 to 24.4.0 (#4493) by @dependabot[bot]
- chore(deps): bump mkdocs-material from 9.6.19 to 9.6.20 in /docs (#4492) by @dependabot[bot]
- chore(deps-dev): bump typedoc from 0.28.12 to 0.28.13 in the typescript group across 1 directory (#4491) by @dependabot[bot]
- chore(deps): bump squidfunk/mkdocs-material from
209b62d
to86d21da
in /docs (#4490) by @dependabot[bot]
This release was made possible by the following contributors:
@dcabib, @dependabot[bot], @dreamorosi, @github-actions[bot], @guillemcomerma, @sdangol, @shrivarshapoojari, @svozza, dependabot[bot] and github-actions[bot]