zapix
v0.2.0
Published
Zapix: Lightweight, Express-style router for AWS Lambda and API Gateway v2. Build serverless APIs with middleware, type safety, and minimal setup.
Maintainers
Readme
Zapix is a lightweight, AWS Lambda–native router for building APIs on any AWS framework (Serverless Framework, SST, CDK, or raw Lambda).
Inspired by Express.js, it gives you familiar routing and middleware on top of Lambda functions — simple, fast, and type-safe.
Build serverless APIs faster. No custom routing logic. Zero learning curve.
🚀 Features
Express-style Routing
Simple
.get(),.post(),.put(),.delete()route definitions.Middleware Support
Chainable middleware functions for authentication, validation, logging, etc.
Error Handling
Global error capturing and customizable error responses.
Utility Helpers
Response(), body parsing, typed route handlers, and more.TypeScript-First
Fully typed interface for safer development and better DX.
Framework-Agnostic
Works with any AWS deployment method or plain Lambda code.
Zapix helps you build clean, scalable serverless (AWS Lambda) APIs, without being tied to any framework or complex routing logic.
📦 Installation
npm install zapix
📌 When to Use Zapix
If you are building a single Lambda function with many API Gateway routes, Zapix handles route matching for you — just like Express.
Zapix is ideal when:
- You use one AWS Lambda to handle multiple routes.
- You want routing behavior similar to Express.js.
- You need clean, reusable middleware.
Example API Gateway paths:
POST /users
GET /users
GET /users/{id}
PUT /users/{id}
DELETE /users/{id}Zapix lets you define these routes exactly like you would in Express, without writing any custom router logic.
🛠 Prerequisites
- AWS Lambda runtime (Node.js)
- API invoked by AWS API Gateway or any Lambda HTTP adapter
🚀 Quick Start
Basic Router Setup
import { Router, Handler } from 'zapix';
const router = new Router();
router.post('/users', createUser);
router.get('/users', readUsers);
router.get('/users/{userId}', readUserInfo);
router.put('/users/{userId}', updateUser);
router.delete('/users/{userId}', deleteUser);
// Fallback route
router.all(() => ({
statusCode: 404,
body: JSON.stringify({ error: 'Route not found' }),
}));
export const handler = Handler(router);🧩 Controllers
A controller handles your business logic for a route.
import { Response, type RouteHandler } from 'zapix';
export const createUser: RouteHandler = async (event, ctx) => {
try {
const body = event.body; // Zapix automatically parses JSON
// Database logic...
return Response(body);
} catch (error) {
return Response(error, 500);
}
};
Tip: Any function returning Response() is considered a controller.
🧱 Middleware
Middleware runs before a controller.
You can chain multiple middleware functions — each must call next() to continue.
import { type RouteMiddleware } from 'zapix';
const authMiddleware: RouteMiddleware = async (event, ctx, next) => {
try {
// Authentication logic...
return next();
} catch (error) {
return next(error);
}
};
router.post('/users', authMiddleware, createUser);
Tip: Calling next(error) stops the request and sends an error response.
🧱➡️ Global Middleware
The Router supports global middleware, allowing you to run middleware logic before any route-specific middleware or handler.
This is useful for cross-cutting concerns such as authentication, logging, request validation, rate limiting, and request context setup.
Registering Global Middleware
Use router.use() to register one or more global middleware functions.
const router = new Router();
router.use(async (event, context, next) => {
console.log(event, context);
await next();
});Global middleware runs for every request, regardless of route. Global middleware fully supports async/await:
Middleware Signature
Global middleware uses the same signature as route middleware:
(event, context, next) =>Promise<void |APIGatewayProxyResultV2>event– API Gateway eventcontext– Lambda contextnext(error?)– Continues execution or triggers error handling
Execution Order
Middleware and handlers execute in the following order:
- Global middleware (in registration order)
- Route-level middleware
- Route handler
- Error handler (if an error occurs)
Example:
router.use(globalMiddleware);
router.get('/example', routeMiddleware, handler);Execution order:
globalMiddleware → routeMiddleware → handlerExample: Auth + Logging
router.use(async (event, context, next) => {
console.log('Incoming request:', event);
await next();
});
router.use(async (event, context, next) => {
if (!event.headers?.authorization) {
throw new Error('Unauthorized');
}
await next();
});🛡 Request Validation Example (Zod + Middleware)
Payload validation is a common middleware use-case. Zapix middleware makes it simple & easy.
1. Validation Helper
// @/helper/zod.ts
import { type z, ZodError } from 'zod';
const formatZodErrorMessages = (error: ZodError) => {
const errors: Record<string, string> = {};
error.issues.forEach((issue) => {
if (issue.path.length) {
errors[issue.path.join('.')] = issue.message;
} else {
errors['extraField'] = issue.message;
}
});
return errors;
};
export const validateRequest = (schema: z.ZodType, data: unknown) => {
try {
schema.parse(data);
return { success: true };
} catch (err) {
if (err instanceof ZodError) {
return { success: false, errors: formatZodErrorMessages(err) };
}
throw err;
}
};
2. Zod Schema
// schema.ts
import { z } from 'zod';
export const UserValidationSchema = z.object({
name: z.string().min(2).max(20),
email: z.string().email(),
address: z.string().optional(),
});
3. Validation Middleware
// index.ts
import { Router, Handler } from 'zapix';
import { z } from 'zod';
import { validateRequest } from '@/helper/zod';
import { UserValidationSchema } from './schema';
const requestValidationMiddleware = (schema: z.ZodType) => {
return async (ctx: any, next: any) => {
const validation = validateRequest(schema, ctx.body);
if (!validation.success) {
return {
statusCode: 400,
body: JSON.stringify({
message: 'Validation failed',
errors: validation.errors,
}),
};
}
return next();
};
};
const router = new Router();
router.post(
'/users',
requestValidationMiddleware(UserValidationSchema),
createUser,
);
router.all(() => ({
statusCode: 404,
body: JSON.stringify({ error: 'Route not found' }),
}));
export const handler = Handler(router);
Tip: Reuse the middleware by passing your Zod schema to apply consistent request validation across multiple APIs.
🧪 Local Testing
You can test Lambda events locally using tools like:
- AWS SAM
- Serverless Framework Offline
- SST Live Lambda Dev
- Local event mock runners
Zapix works with any Lambda simulator.
📝 License
MIT License
© Raihan Sharif, Software Engineer | BrillMark LLC
