TypeScript is an excellent language for writing AWS Lambda functions. Its flexible static typing allows for high developer productivity and since it can be transpiled into JavaScript, our code can be bundled into small deployment packages that allow for fast Lambda cold starts, without need for keeping 'warm' instances of our lambdas.
I have recently added a new template to the Goldstack template library, Serverless API, that provides an easy starting place for developing a REST API using AWS Lambda. It took me quite a while to figure out the correct types to use for the handlers, so I thought I quickly document that here in this blog post.
When developing a handler for a Lambda function, we need to work with three structured objects:
-
event
: Which contains information about the specific invocation of the Lambda. -
context
: Which contains information about the Lambda function itself. -
result
: In which we define the response for the Lambda invocation.
The types of these objects differs depending on the type of integration we have defined for our Lambda; they will contain different data depending on whether the Lambda is invoked directly or whether the Lambda is called in response to an incoming HTTP request in an API Gateway.
Given the many integrations available for the AWS Lambda service, there are many different combinations of types for the Lambda handler function.
While the core aws-skd does not provide the types we require, the heavy lifting for this has thankfully been done in the module @types/aws-lambda. This package offers types for most types of events and results for Lambda functions.
Note that there is also a package called aws-lambda. This package provides CLI helper tools for Lambda deployment but not the types we are looking for. Thus it is important to ensure adding the correct package with:
yarn add -D @types/aws-lambda
npm i @types/aws-lambda --save-dev
Unfortunately, the documentation of @types/aws-lambda leaves a bit to be desired, specifically when it comes to defining integrations for AWS API Gateway. This confused me quite a bit, especially since AWS now offers two flavours of API Gateway: with a REST and an HTTP API. Thus I provide below a reference for a number of common types for Lambda integrations:
AWS API Gateway HTTP and REST API Proxy Integration V1.0
For version 1.0 of both the REST API proxy integration and HTTP API proxy integration use this handler signature:
export type APIGatewayProxyHandler = Handler<APIGatewayProxyEvent, APIGatewayProxyResult>;
AWS API Gateway HTTP and REST API Proxy Integration V2.0
For version [2.0] use this handler signature:(https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html)
export type APIGatewayProxyHandlerV2<T = never> = Handler<APIGatewayProxyEventV2, APIGatewayProxyResultV2<T>>;
export interface APIGatewayEventRequestContextV2 { ... }
Note that under version 2.0
the result of the invocation can an object or a string as well, so the following are also valid declarations for the handler (see Lambda function response format):
export type APIGatewayProxyHandlerV2<T = never> = Handler<APIGatewayProxyEventV2, any>;
export type APIGatewayProxyHandlerV2<T = never> = Handler<APIGatewayProxyEventV2, string>;
If possible, replace any
with your own custom type.
Find below a few examples for handlers:
$default.ts: Using APIGatewayProxyResultV2
import {
Handler,
APIGatewayProxyEventV2,
APIGatewayProxyResultV2,
} from 'aws-lambda';
type ProxyHandler = Handler<APIGatewayProxyEventV2, APIGatewayProxyResultV2>;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export const handler: ProxyHandler = async (event, context) => {
return {
statusCode: 201,
body: JSON.stringify({
message: 'Unknown endpoint',
}),
};
};
echo.ts: Returning a custom object.
import { Handler, APIGatewayProxyEventV2 } from 'aws-lambda';
type ProxyHandler = Handler<APIGatewayProxyEventV2, any>;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export const handler: ProxyHandler = async (event, context) => {
const message = event.queryStringParameters?.message || 'no message';
return {
message: `${message}`,
};
};
Find further information on the above referenced types in api-gateway-proxy.d.ts.
Top comments (0)