@tomkrcmar/lambda-router v0.0.6
@tomkrcmar/lambda-router
A general purpose middleware, route modeling, and route matching framework.
Features:
- Familiar, express-like interface
- Nested routers and relative route matching
- Exact or inexact route matching
- Route parameter matching
- Optional routes or route params
- Extendable, integrate with any server framework like Lambda, express, etc.
- Comes with an implementation for routing in Lambda functions
Usage:
There is no official documentation, but a good way to see example usage is the unit tests.
Instantiate a Router
import { Router } from '@tomkrcmar/lambda-router';
const router = new Router();Simple HTTP request
// "get" can also be post, put, patch, delete
router.get('/hello', (req, res) => {
res.send('Hello, World!');
})Route parameters
router.get('/thing/:id', (req, res) => {
const { id } = req.params;
res.send(`Thing data for thing number ${id}`);
})Optional route parameters
router.get('/thing/:id?', (req, res) => {
const { id } = req.params;
if (id)
res.send(`Thing data for thing number ${id}`);
else
res.send('Thing index for all things');
})
// Regular text routes can also be optional:
router.get('path/to?/something?/maybe?', (req, res) => {
// This matches path, path/to, path/to/something, and path/to/something/maybe
});Simple Middleware
router.use((req, res, ctx) => {
// All 3 arguments have their own `data` property for custom props passed down to subsequent middleware
req.data.myCustomValueA = 5;
res.data.myCustomValueB = 6;
ctx.data.myCustomValueC = 7;
// Allow subsequent middleware and route matching to continue
ctx.next();
// Note: ctx also contains other misc. information about the current router stack and dispatching state.
})Nested Routers example
const thingRouter = new Router();
thingRouter.get('thing', (req, res) => {
res.send('Thing data');
})
router.use('/path/to/the', thingRouter);
// At this point, GET /path/to/the/thing will match the handlerMethod chaining (set status code, set one header, set multiple headers, send with body)
router.get('/hello', (req, res) => {
res.status(200)
.header('Content-type', 'text/plain')
.setHeaders({
'X-Header-One': 'ABC',
'X-Header-Two': '123',
})
.send('Hello, World!');
})CORS middlware example
import { Router } from '@tomkrcmar/lambda-router';
const router = new Router();
export default router;
router.use((req, res, ctx) => {
res.setHeaders({
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET,POST,PUT,PATCH,DELETE',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Headers': 'Content-Type,Authorization',
});
if (req.method === 'options')
res.status(200).send();
else
ctx.next();
})Lambda Handler:
Simply add your routes on a LambdaRouter at the top level and supply it to your handler export in lambda. The rest of your app can be built with Routers and are completely portable, only the top-level router needs to be a LambdaRouter.
There are multiple LambdaRouters available, but the default LambdaRouter will attempt to detect the right version:
LambdaRouter- Auto-detect API Gateway API versionApiGatewayLambdaRouter- API Gateway V1 REST APIsApiGatewayV2LambdaRouter- API Gateway V2 HTTP APIs
Minimal example
import { LambdaRouter } from '@tomkrcmar/lambda-router';
import myAppRouter from './my-app';
export function handler(event, context) {
return new LambdaRouter().use(myAppRouter).dispatchLambda(event, context);
}Example of adding our CORS middleware above, and a hello world endpoint directly onto the top-level router:
import { LambdaRouter } from '@tomkrcmar/lambda-router';
import cors from './my-middleware/cors';
const router = new LambdaRouter();
router.use(cors);
router.get('/hello', (req, res) => {
res.send('Hello, World!');
})
export function handler(event, context) {
return router.dispatchLambda(event, context);
}Custom Integration:
In order to integrate your route model into a server framework, there are three steps:
- Construct a
Request - Call
Router.dispatch(request) - Handle the
Response
The LambdaRouter above performs all of these steps for you, constructing a Request from your lambda event and context, and converting the Response to the lambda handler response structure that lambda expects.
Minimal example of manually doing this with no conversion:
import { Request, Router } from '@tomkrcmar/lambda-router';
const router = new Router();
router.use('/hello', (req, res) => res.send('Hello, World!'))
const req = new Request();
req.path = '/hello';
const res = await router.dispatch(req);
// res.body should now be populated with 'Hello, World!' with status code 200 and other misc. fields presentInstallation
# Install as a runtime dependency
npm install --save @tomkrcmar/lambda-router
# Install as a development dependency if you have your own build or bundling process
npm install --save-dev @tomkrcmar/lambda-routerBuilding and Testing
Build the module yourself:
npm run build
# Build in watch mode:
npm run build:wRun unit tests and coverage:
npm run test
# Test in watch mode:
npm run test:w