Basic Type-Safe Setup
import{API,Request,Response,ALBContext,APIGatewayContext,APIGatewayV2Context}from'lambda-api';import{ALBEvent,APIGatewayProxyEvent,APIGatewayProxyEventV2}from'aws-lambda';// Initialize with type inferenceconstapi=newAPI();Type-Safe Request Handlers
ALB Handler Example
interfaceUserData{id:string;name:string;email:string;}// Type-safe ALB request handlerapi.get<UserData,ALBContext>('/users',(req,res)=>{// req.requestContext is typed as ALBContextconsole.log(req.requestContext.elb.targetGroupArn);// Type-safe responseres.json({id:'123',name:'John Doe',email:'john@example.com'});});API Gateway v1 Handler Example
// Type-safe API Gateway v1 request handlerapi.post<UserData,APIGatewayContext>('/users',(req,res)=>{// req.requestContext is typed as APIGatewayContextconsole.log(req.requestContext.requestId);console.log(req.requestContext.identity.sourceIp);res.json({id:req.requestContext.requestId,name:req.body.name,email:req.body.email});});API Gateway v2 Handler Example
// Type-safe API Gateway v2 request handlerapi.put<UserData,APIGatewayV2Context>('/users/:id',(req,res)=>{// req.requestContext is typed as APIGatewayV2Contextconsole.log(req.requestContext.http.sourceIp);res.json({id:req.params.id,name:req.body.name,email:req.body.email});});Type-Safe Middleware
Source-Agnostic Middleware
import{Middleware,isApiGatewayContext,isApiGatewayV2Context,isAlbContext}from'lambda-api';constsourceAgnosticMiddleware:Middleware=(req,res,next)=>{// Type guards help narrow down the request context typeif(isAlbContext(req.requestContext)){// ALB specific logicconsole.log(req.requestContext.elb.targetGroupArn);}elseif(isApiGatewayV2Context(req.requestContext)){// API Gateway v2 specific logicconsole.log(req.requestContext.http.sourceIp);}elseif(isApiGatewayContext(req.requestContext)){// API Gateway v1 specific logicconsole.log(req.requestContext.identity.sourceIp);}next();};api.use(sourceAgnosticMiddleware);Source-Specific Middleware
// ALB-specific middlewareconstalbMiddleware:Middleware<any,ALBContext>=(req,res,next)=>{// req.requestContext is typed as ALBContextconsole.log(req.requestContext.elb.targetGroupArn);next();};// API Gateway v2 specific middlewareconstapiGwV2Middleware:Middleware<any,APIGatewayV2Context>=(req,res,next)=>{// req.requestContext is typed as APIGatewayV2Contextconsole.log(req.requestContext.http.sourceIp);next();};Type-Safe Error Handling
import{ErrorHandlingMiddleware}from'lambda-api';consterrorHandler:ErrorHandlingMiddleware=(error,req,res,next)=>{if(isAlbContext(req.requestContext)){// ALB specific error handlingres.status(500).json({message:error.message,targetGroup:req.requestContext.elb.targetGroupArn});}else{// Default error handlingres.status(500).json({message:error.message});}};api.use(errorHandler);Advanced Type-Safe Examples
Custom Request Types
interfaceCustomQuery{filter?:string;page?:string;}interfaceCustomParams{userId:string;}interfaceCustomBody{name:string;email:string;}// Fully typed request handlerapi.get<UserData,ALBContext,CustomQuery,CustomParams,CustomBody>('/users/:userId',(req,res)=>{// All properties are properly typedconst{ filter, page}=req.query;const{ userId}=req.params;const{ name, email}=req.body;res.json({id:userId, name, email});});Response Type Extensions
// Extend Response interface with custom methodsdeclare module'lambda-api'{interfaceResponse{sendWithTimestamp?:(data:any)=>void;}}constresponseEnhancer:Middleware=(req,res,next)=>{res.sendWithTimestamp=(data:any)=>{res.json({ ...data,timestamp:Date.now()});};next();};api.use(responseEnhancer);// Use custom response methodapi.get('/users',(req,res)=>{res.sendWithTimestamp({name:'John'});});Using Built-in Auth Property
interfaceAuthInfo{userId:string;roles:string[];type:'Bearer'|'Basic'|'OAuth'|'Digest'|'none';value:string|null;}functionhasAuth(req:Request):req isRequest&{auth:AuthInfo}{return'auth'inreq&&req.auth?.type!==undefined;}api.get('/protected',(req,res)=>{if(hasAuth(req)){// req.auth is now typed as AuthInfoconst{ userId, roles}=req.auth;res.json({ userId, roles});}else{res.status(401).json({message:'Unauthorized'});}});Running the API
// Type-safe run methodexportconsthandler=async(event:ALBEvent|APIGatewayProxyEvent|APIGatewayProxyEventV2,context:any)=>{returnapi.run(event,context);};Type Guards Usage
import{isAlbContext,isAlbEvent,isAlbRequest,isApiGatewayContext,isApiGatewayEvent,isApiGatewayRequest,isApiGatewayV2Context,isApiGatewayV2Event,isApiGatewayV2Request}from'lambda-api';api.use((req,res,next)=>{// Event type guardsif(isAlbEvent(req.app._event)){// ALB specific logic}// Context type guardsif(isAlbContext(req.requestContext)){// ALB specific logic}// Request type guardsif(isAlbRequest(req)){// ALB specific logic}next();});Best Practices
- Always specify response types for better type inference:
interfaceResponseType{message:string;code:number;}api.get<ResponseType>('/status',(req,res)=>{res.json({message:'OK',code:200});});- Use type guards for source-specific logic:
api.use((req,res,next)=>{if(isAlbContext(req.requestContext)){// ALB-specific loggingconsole.log(`ALB Request to${req.requestContext.elb.targetGroupArn}`);}next();});- Leverage TypeScript's type inference with middleware:
consttypedMiddleware:Middleware<ResponseType,ALBContext>=(req,res,next)=>{// Full type information availablenext();};- Use source-specific error handling:
api.use((error,req,res,next)=>{constbaseError={message:error.message,timestamp:newDate().toISOString()};if(isAlbContext(req.requestContext)){res.status(500).json({ ...baseError,targetGroup:req.requestContext.elb.targetGroupArn});}elseif(isApiGatewayV2Context(req.requestContext)){res.status(500).json({ ...baseError,stage:req.requestContext.stage});}else{res.status(500).json(baseError);}});Issues
implements#276
andcloses#244
Uh oh!
There was an error while loading.Please reload this page.
Basic Type-Safe Setup
Type-Safe Request Handlers
ALB Handler Example
API Gateway v1 Handler Example
API Gateway v2 Handler Example
Type-Safe Middleware
Source-Agnostic Middleware
Source-Specific Middleware
Type-Safe Error Handling
Advanced Type-Safe Examples
Custom Request Types
Response Type Extensions
Using Built-in Auth Property
Running the API
Type Guards Usage
Best Practices
Issues
implements#276
andcloses#244