A small framework, with very few dependencies to help build applications using AWS Lambda.
Visit vacasaoss.github.io/lambaa for more docs.
npm i lambaa
npm i @types/aws-lambda -D
Have a look at a Serverless project created using the aws-nodejs-typescript
template.
This library has the concept of controllers, similar to other web frameworks.
To create a controller, add the @Controller()
decorator to a class and define routes using one of the route decorators, e.g. @GET("/ping")
.
import { Controller, GET, POST } from "lambaa"
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda"
@Controller()
class UserController {
@GET("/user")
public getUser(event: APIGatewayProxyEvent): APIGatewayProxyResult {}
@POST("/user")
public addUser(event: APIGatewayProxyEvent): APIGatewayProxyResult {}
}
The following event types are supported in addition to API Gateway events.
Function | Event Type |
---|---|
@SQS() |
SQSEvent |
@Schedule() |
ScheduledEvent |
@DynamoDB() |
DynamoDBStreamEvent |
@Kinesis() |
KinesisStreamEvent |
@EventBridge() |
EventBridgeEvent |
@S3() |
S3Event |
@SNS() |
SNSEvent |
See more documentation about the supported event handler decorators here.
Create an index.ts
file and export the handler.
import { Router } from "lambaa"
const router = new Router().registerController(new PingController())
export const handler = router.getHandler()
Your handler can be referenced in your serverless.yml
as follows:
functions:
ping:
handler: src/index.handler
events:
- http:
path: ping
method: get
See the Serverless example project for an example of how to use with
serverless.ts
.
Generic proxy resources are also supported using the {proxy+}
path variable.
This can simplify the handler setup by allowing you to configure a single event to handle many different HTTP requests.
events:
- http:
path: /{proxy+}
method: ANY
Note: if you choose to use a proxy resource, API Gateway will forward all matching HTTP requests to your Lambda function. This will result in an error if the route is not handled by your application. It is recommended to handle this error using a middleware. Check for the
RouterError
type.
Middleware can be used to modify the request/response pipeline.
You can define middleware by using the Middleware
, or MiddlewareFunction
interfaces.
import { MiddlewareFunction } from "lambaa"
const middleware: MiddlewareFunction = async (event, context, next) => {
// Operate on the request here
// Pass the event to the next middleware
const response = await next(event, context)
// Operate on the response here
return response
}
import { Middleware, Handler } from "lambaa"
import {
APIGatewayProxyEvent,
APIGatewayProxyResult,
Context,
} from "aws-lambda"
class LogRequestMiddleware implements Middleware {
public async invoke(
event: APIGatewayProxyEvent,
context: Context,
next: Handler
): Promise<APIGatewayProxyResult> {
console.log(
`Received request - method: ${event.httpMethod}, resource: ${event.resource}`
)
const response = await next(event, context)
return response
}
}
The default middleware event/result types can be changed by specifying generic type parameters.
const sqsMiddleware: MiddlewareFunction<SQSEvent, void> = async (
event,
context,
next
) => {
// ...
}
Middleware can be added to a controller method directly, by using the @Use()
decorator.
@Use(new AuthenticationMiddleware())
@Use(new LogRequestMiddleware())
@GET("/ping")
public ping(event: APIGatewayProxyEvent) {
return {
statusCode: 200,
body: "pong",
}
}
They can also be applied by being passed to the @Controller()
decorator.
@Controller({ middleware: [new LogRequestMiddleware()] })
class PingController {}
Finally, they can be applied globally using the Router
.
export const handler = new Router()
.registerController(new PingController())
.registerMiddleware(new LogRequestMiddleware())
.getHandler()
Parameter decorators can be used to extract the parts of the request which we need.
@GET("/user/{id}")
public getUser(
@FromHeader("Accept") accept: string,
@FromPath("id") id: string,
) {
return {
statusCode: 200,
body: ""
}
}
Function | Description | Type |
---|---|---|
@FromPath() |
Extract a path parameter | string |
@FromQuery() |
Extract a query string parameter | string |
@FromBody() |
Extract JSON body data | any |
@FromHeader() |
Extract header value | string |
If the required request parameters cannot be found, a RequestError
will be thrown.
It is recommended to handle this using a middleware.
class HandleRequestErrorMiddleware implements Middleware {
public async invoke(
event: APIGatewayProxyEvent,
context: Context,
next: Handler
): Promise<APIGatewayProxyResult> {
try {
return await next(event, context)
} catch (err) {
if (err instanceof RequestError) {
return {
statusCode: 400,
body: JSON.stringify({
code: err.code,
}),
}
}
throw err
}
}
}