Skip to content

Repository files navigation

Type-safe middleware for AWS Lambda

Leveraging the power of Typescript to build middleware-like request handlers for lambda functions with type-based dependency checking.

TypeScriptTestCoverage Status

Gif

An example

A service which parse request body as JSON, get a and b from it, check if both are valid numbers, then adds them and return result.

import{Err,MiddlewareCreator,Handler,JsonBodyService,ok,fail,creator,addService,jsonBodyService}from'lambda-mdl';typeNumberService={a: number;b: number};typeNumberErrNaN=Err<'NaA'>;typeNumberDependencies=JsonBodyService;constnumbers: MiddlewareCreator<{},NumberService,NumberErrNaN,NumberDependencies>=()=>{returnasync(request)=>{constbody=request.service.jsonBody;if(!(Number.isFinite(body.a)&&Number.isFinite(body.b))){returnfail<NumberErrNaN>('NaA');}constservice=bodyasNumberService;returnaddService(request,service);};};typeOptions={acceptFloat: boolean};typeAdderService={add: (a: number,b: number)=>number};typeAdderErrNoFloats=Err<'Float'>;constadder: MiddlewareCreator<Options,AdderService,AdderErrNoFloats>=(options,{ throws })=>{constservice: AdderService={add: (a: number,b: number)=>{if(!options.acceptFloat&&!(Number.isInteger(a)&&Number.isInteger(b))){throws<AdderErrNoFloats>('Float');}returna+b;},};returnasync(request)=>{returnaddService(request,service);};};consthandler: Handler<AdderService&NumberService,number,never>=async({service: { a, b, add },})=>{returnok(add(a,b));};constlambda=creator(jsonBodyService).srv(numbers).srv(adder).ok(handler);

API

Defining services

Static service:

MiddlewareCreator

Type used for creating new services.

Params:

  • Options
  • Service
  • Errors
  • ServiceDeps
  • Event
import{Err,MiddlewareCreator,addService}from'lambda-mdl';typeOptions={};typeService={add: (a: number,b: number)=>number};typeErrors=never;constservice: MiddlewareCreator<Options,Service,Errors>=()=>{returnasync(request)=>{returnaddService(request,{add: (a: number,b: number)=>{returna+b;},});};};
Dynamic service:

Middleware

Used to define services dynamically based on provided options.

Params:

  • Service
  • Errors
  • ServiceDeps
  • Event
import{Middleware,ServiceContainer,Request,AwsEvent,empty,addService,creator}from'lambda-mdl';typeOptions={test: number};typeService<Opt>=Opt;typeErrors=never;constservice=<OptextendsOptions>(options: Partial<Opt>): Middleware<Opt,{data: Service<Opt>},Errors>=>{returnasync<SrvextendsServiceContainer>(request: Request<AwsEvent,Opt,Srv>)=>{returnaddService(request,{data: {test: options.test}asService<Opt>,});};};constres=creator(empty).opt({test: 1}).srv(service);

Initialization

creator

Starts the creation of the lambda chain.

Params:

  • creator: MiddlewareCreator
import{creator,empty}from'lambda-mdl';constres=creator(empty);// now you can use other methods, for example: .srv 

srv

Adds a new service.

Params:

  • creator: MiddlewareCreator
import{MiddlewareCreator,creator,empty,addService}from'lambda-mdl';constservice: MiddlewareCreator<{},{},never>=()=>{returnasync(request)=>{returnaddService(request,{});}};constres=creator(empty).srv(service);

opt

Set the options.

Params:

  • options

Handlers

ok

Adds a handler which will be run if all middleware creators executed successfully.

Params:

  • handler: Handler
import{ok,creator,empty}from'lambda-mdl';constres=creator(empty).ok(async()=>{returnok('success');// can be used in onOk});

fail

Adds a handler which runs on middleware failure.

Params:

  • handler: HandlerError
import{ok,creator,empty}from'lambda-mdl';constres=creator(empty).fail(async()=>{// this handler will not run because // empty middleware won't failreturnok('success');// can be used in onFail});

fatal

Adds an unknown exception handler.

Params:

  • handler: HandlerException
import{ok,creator,empty}from'lambda-mdl';constres=creator(empty).fatal(async()=>{// this handler will not run because // empty middleware won't throw fatal errorsreturnok('success');// can be used in onFatal});

Transforms

onOk, onOkRes

Sets the result transformation of ok handler.

Params:

  • transform: Transform
import{ok,creator,empty}from'lambda-mdl';constres=creator(empty).ok(async()=>{returnok('success');}).onOk(async(result)=>{returnresult;// result equals to 'success'});

onFail, onFailRes

Sets the result transformation of fail handler.

Params:

  • transform: TransformError
import{ok,creator,empty}from'lambda-mdl';constres=creator(empty).fail(async()=>{returnok('fail');}).onFail(async(result)=>{returnresult;// result equals to 'fail'});

onFatal, onFatalRes

Sets the result transformation of fatal handler.

Params:

  • transform: TransformError
import{ok,creator,empty}from'lambda-mdl';constres=creator(empty).fatal(async()=>{returnok('fatal');}).onFatal(async(result)=>{returnresult;// result equals to 'fatal'});

on

Same as calling onOk, onFail and onFatal.

req

Returns AWS Lambda handler.


Packages

Packages allow grouping a service, and ok and fail handlers together.

import{Err,fail,ok}from'lambda-res';import{creator,empty,addService,ServiceOptions,Package}from'lambda-mdl';constpack: Package<ServiceOptions,{packageService: string},Err<'ServiceError'>,string,never,string>={srv: ()=>{returnasync(request)=>{returnaddService(request,{packageService: 'service test',});};},ok: async()=>{returnok(`ok`);},fail: async()=>{returnok(`fail`);},};creator(empty).pack(pack).ok(async({service: { packageService }})=>{returnok(packageService);});

Used by

Contributors

Languages