This project provides a universal AWS Lambda entry point implemented in Node.js. It inspects each incoming event and automatically routes it to the appropriate handler based on the invocation source.
Clone the repository and install the development dependencies used for testing and linting:
npm installThis project requires Node.js 20 or later, as specified in
package.json.
Type declaration files are included for all handlers. Run npm run build to regenerate them after making changes.
Zip the contents of the repository and upload them using the AWS CLI:
zip -r function.zip index.mjs handlers/
aws lambda create-function \
--function-name universal-handler \
--runtime nodejs20.x \
--handler index.handler \
--zip-file fileb://function.zip \
--role <role-arn>To update an existing function:
zip -r function.zip index.mjs handlers/
aws lambda update-function-code \
--function-name universal-handler \
--zip-file fileb://function.zipThe handler recognizes and dispatches events from:
- Alexa Skills Kit
- Amazon Lex bots
- AWS AppSync (GraphQL resolvers)
- IoT Rules
- Kinesis Firehose data transformation
- AWS Config rules
- Step Functions tasks
- WebSocket APIs
- API Gateway authorizers (v1 and v2)
- API Gateway HTTP APIs (v1 and v2)
- Application Load Balancers
- Lambda@Edge
- CloudWatch Logs subscriptions
- CloudFormation custom resources
- Cognito triggers
- SQS, SNS, S3, DynamoDB Streams, Kinesis Streams, SES
- EventBridge / CloudWatch Events
- Scheduled events
- Fallback for other events
Handlers and event checks are listed in dispatch-config.js. Each entry
contains a check function that inspects the incoming event and a handler
module path. The dispatcher loads this file during initialization.
To add your own event type:
- Create a new module under
handlers/exporting a default async function. - Add an object to
dispatch-config.jswith your detection logic and handler path.
Example:
// dispatch-config.js
export default [
// existing entries...
{ check: e => e.myField === 'custom', handler: './handlers/handleMyEvent.js' },
];HTTP API v1 request:
{
"httpMethod": "GET",
"path": "/hello"
}S3 event:
{
"Records": [
{
"eventSource": "aws:s3",
"s3": {
"bucket": { "name": "my-bucket" },
"object": { "key": "file.txt" }
}
}
]
}EventBridge event:
{
"source": "my.app",
"detail-type": "example",
"detail": {"key": "value"}
}Handler modules live in the handlers/ folder and export a single async
function. A minimal handler looks like:
export default async function handleSomething(event, context) {
// your logic here
}When a Lambda invocation occurs, index.mjs obtains the dispatch
table and executes the first handler whose check function matches the event:
const dispatchTable = await dispatchTablePromise;
for (const { check, handler: h } of dispatchTable) {
if (check(event)) {
return await h(event, context);
}
}If no entry matches, handleDefault.js is called.
- Create a new file in
handlers/exporting a default async function. - Import the file in
dispatcher.jsand add it tohandlerMap. - Add a
checkentry indispatch-config.jsthat returnstruefor your event type and references the handler path. - Add unit tests in
tests/verifying the dispatch and response. Use existing cases intests/handlers.test.jsas a guide. - Run
npm testto ensure all tests pass.
Run the unit tests with:
npm testInvoke the handler locally with a JSON event file:
npm run invoke -- examples/http-v1.jsonSample payloads for all supported sources live under the examples/ directory.
Issues and pull requests are welcome. If adding new handlers or tests, please follow the existing code style and include relevant documentation.
After deploying, invoke the Lambda with your event payload. For example:
aws lambda invoke \
--function-name universal-handler \
--payload '{"httpMethod":"GET","path":"/"}' output.jsonSet DEBUG=1 (or any non-empty value) to enable additional log output. This can help troubleshoot event dispatching and handler execution.
When invocation data is collected, functions on the context object are invoked. If a context function throws an error, its message is captured and included in the logged context instead of halting execution.