Auto-loading, self-validating, minimalist JavaScript library for Amazon Web Service Lambdas
Acai delivers a DRY, configurable, declarative experience for building AWS Lambda integrations in JavaScript. It encourages Happy Path Programmingβvalidate inputs first, eliminate defensive code, and keep business logic focused on success paths.
Need TypeScript bindings? Check out the companion package acai-ts for a fully typed experience.
Full Documentation Β· Examples Β· Tutorial
- π Zero Boilerplate β File-based routing auto-loads handlers with minimal configuration.
- β Built-in Validation β OpenAPI schema validation for API Gateway and event sources.
- π§© Extensible Middleware β Compose
before,after,withAuth, andbeforeAll/afterAllhooks effortlessly. - π Event Helpers β Uniform abstractions for DynamoDB, S3, and SQS events with operation filtering.
- π§ͺ Test Friendly β Lightweight surface area and deterministic responses make unit tests straightforward.
- π Serverless Friendly β Designed to slot into Serverless Framework, SAM, or raw Lambda stacks.
Validate early, then write business logic without guardrails and nested try/catch blocks. Acai pushes error handling to the edges, keeping the core flow clean and intention-revealing.
const {Router} = require('acai').apigateway;
const router = new Router({
basePath: 'v1',
handlerPath: 'src/handlers', // auto-expanded to src/handlers/**/*.js
schemaPath: 'openapi.yml', // optional: enable OpenAPI validation
autoValidate: true, // validate requests automatically
validateResponse: true // validate responses before returning
});
exports.handler = async (event) => {
return await router.route(event);
};
// File: src/handlers/users/index.js
exports.requirements = {
post: {
requiredBody: 'CreateUserRequest'
}
};
exports.post = async (request, response) => {
response.body = {
id: '123',
email: request.body.email
};
return response;
};const router = new Router({
basePath: 'api/v1',
handlerPattern: 'src/controllers/**/*.controller.js'
});Both handlerPath and handlerPattern feed the same resolver. handlerPath is shorthand for directory-style routing (**/*.js), while handlerPattern supports custom naming conventions.
const {dynamodb} = require('acai');
exports.handler = async (event) => {
const ddbEvent = new dynamodb.Event(event, {
operations: ['create', 'update'],
globalLogger: true
});
for (const record of ddbEvent.records) {
console.log('Operation:', record.operation);
console.log('New values:', record.body);
console.log('Old values:', record.oldImage);
}
};const {s3} = require('acai');
exports.handler = async (event) => {
const s3Event = new s3.Event(event, {
getObject: true,
isJSON: true
});
const records = await s3Event.getRecords();
for (const record of records) {
console.log('Bucket:', record.bucket.name);
console.log('Key:', record.key);
console.log('Parsed body:', record.body);
}
};npm install acai- Node.js: β₯ 22.19.0
npm install
npm testWe welcome issues, feature requests, and pull requests! Please review the guidelines in CONTRIBUTING.md before you start. If you release a bug fix or enhancement, add an entry to CHANGELOG.md describing the change.
- .agents/AGENTS.md β Contributor quick-start for day-to-day workflows and expectations.
- .agents/ARCHITECTURE.md β High-level design notes for the runtime and adapters.
- .agents/WARP.md β Operational guidance and runbooks for automation agents.
- acai-ts β TypeScript-first implementation with decorators and type metadata.