Skip to content

A small framework, with very few dependencies to help build API's using AWS API Gateway & Lambda.

License

Notifications You must be signed in to change notification settings

vacasaoss/lambaa

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

48 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

lambaa ๐Ÿ‘

A small framework, with very few dependencies to help build applications using AWS Lambda.

Visit vacasaoss.github.io/lambaa for more docs.

Installation

npm i lambaa
npm i @types/aws-lambda -D

Example Project

Have a look at a Serverless project created using the aws-nodejs-typescript template.

Guide

Controllers

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 {}
}

Other Supported Events

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.

Setup

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()

Use With Serverless (serverless.yml)

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.

API Gateway Generic Proxy Resources

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

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
) => {
    // ...
}

Applying Middleware

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()

Request Parsing

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
Request Parsing Errors

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
        }
    }
}