lambdalith
v0.4.1
Published
A tiny event router for AWS Lambda functions. Route SQS, SNS, EventBridge, and DynamoDB Streams events with a fluent API.
Maintainers
Readme
Lambdalith
A lightweight, type-safe event router for AWS Lambda functions. Route SQS, SNS, EventBridge, and DynamoDB Streams events with a fluent API.
Features
- 🔍 Automatic event detection – Identifies incoming event types without configuration.
- 📦 Per-record processing – Handles batch events record-by-record in parallel or sequentially with partial failure support.
- 🎯 Route matching – Filter by queue name, topic, source/detail-type, or table name.
- ⚠️ Built-in error handling – Handle errors and unmatched events with ease.
- 🦺 Full TypeScript support – Strongly typed contexts with auto-completion.
- 🔧 Middleware support – Run middleware before and after handling each record.
- 🪶 Lightweight – Zero dependencies.
Installation
npm install lambdalithQuick Start
import { EventRouter } from 'lambdalith';
const router = new EventRouter();
router.sqs('MyQueue', (c) => {
console.log(c.sqs.body);
});
router.sns('MyTopic', (c) => {
console.log(c.sns.body);
});
router.event({ source: 'MyService', detailType: 'MyEvent' }, (c) => {
console.log(c.event.detail);
});
router.dynamodb('MyTable', (c) => {
console.log(c.dynamodb.newImage);
});
router.onError((error, c) => {
console.error(error.message);
});
router.notFound((c) => {
console.warn('Unhandled', c.source);
});
export const handler = router.handler();Route Matching
Routes are matched in registration order – the first matching route wins. Register specific routes before catch-alls:
router.sqs('SpecificQueue', (c) => {
// will match the specific queue
});
router.sqs((c) => {
// will match any other queue
});Batch Processing
For SQS and DynamoDB Streams, the router automatically handles partial batch failures. Enable ReportBatchItemFailures on your function to take advantage of this feature.
Default (parallel): All records process concurrently. Failed records reported individually.
Sequential: Records process one at a time. Stops processing on failure and marks remaining records as failed.
router.sqs(
'MyQueue.fifo',
(c) => {
// will process messages from my-queue sequentially
},
{ sequential: true },
);Context
Each handler receives a context object with event-specific data and the Lambda context:
router.sqs((c) => {
c.sqs; // SQS context
c.lambda; // Lambda context
});Error Handling
When an error handler is registered, errors are swallowed by default. To propagate an error (mark the record as failed or fail the invocation), rethrow it:
// Swallow error (log and continue)
router.onError((error, c) => {
console.error(error.message);
});
// Propagate error (rethrow to fail)
router.onError((error, c) => {
console.error(error.message);
throw error; // Record marked as failed / invocation fails
});If you do not register an error handler, errors always propagate to the router which will mark the record as failed.
// Called when no route matches
router.notFound((c) => {
console.warn('Unhandled:', c.source);
console.log(c.raw);
});Middleware
Middleware runs for each record in onion-style order. The first registered middleware wraps the last:
middleware1
middleware2
handler
middleware2
middleware1Add a middleware to the router:
router.use(async (c, next) => {
console.log('before');
await next();
console.log('after');
});Middleware must call next() to continue. Returning without calling next() skips the rest of the middleware chain and the handler, treating the event as successfully handled.
Filter middleware by event type:
router.use('sqs', async (c, next) => {
// Only runs for SQS events
await next();
});
router.use('sns', snsMiddleware);
router.use('event', eventBridgeMiddleware);
router.use('dynamodb', dynamodbMiddleware);Testing
Use router.test() to send test events to the router to ensure your handlers are called correctly.
describe('Example', () => {
const testRouter = router.test();
test('sqs routing', async () => {
const res = await testRouter.send.sqs({
queue: 'orders-queue',
body: { orderId: '123' },
});
expect(res).toEqual({ batchItemFailures: [] });
}
})Contributing
Please see CONTRIBUTING.md for contribution guidelines.
License
MIT
