how.wtf

Deploy serverless Lambda TypeScript API with function url using AWS CDK

· Thomas Taylor

In November 2023, I wrote a post describing how to deploy a lambda function with a function url in Python. For this post, I want to showcase how streamlined and practical it is to deploy a “Lambdalith” (a single Lambda function) that contains an entire API.

What this means:

  1. No API Gateway
  2. API requests can take longer than 30 seconds
  3. Faster deployments
  4. Local testing without cloud deployment
  5. Reduced costs *
  6. Easy management *

How to deploy a serverless API using Fastify

To begin, let’s initialize a CDK application for Typescript:

cdk init app --language typescript

This creates the boilerplate directories and files we’ll need:

 1serverless-api
 2├── README.md
 3├── bin
 4│   └── serverless-api.ts
 5├── cdk.json
 6├── jest.config.js
 7├── lib
 8│   └── serverless-api-stack.ts
 9├── package-lock.json
10├── package.json
11├── test
12│   └── serverless-api.test.ts
13└── tsconfig.json

Install and configure Fastify

Fastify is a JavaScript web framework that intentionally aims for low overhead and speed over other frameworks such as express. I have arbitrarily chose it for this tutorial, but any web framework that supports routing will work.

Install fastify

Install fastify using one of the methods described in their documentation and their AWS Lambda adapter @fastify/aws-lambda.

For this tutorial, I’ll use npm.

npm i fastify @fastify/aws-lambda @types/aws-lambda

Create an entry file

To make it easy, we’ll create an entry point for the lambda at handler/index.ts with the following contents:

 1import Fastify from "fastify";
 2import awsLambdaFastify from "@fastify/aws-lambda";
 3
 4function init() {
 5  const app = Fastify();
 6  app.get('/', (request, reply) => reply.send({ hello: 'world' }));
 7  return app;
 8}
 9
10if (require.main === module) {
11  // called directly i.e. "node app"
12  init().listen({ port: 3000 }, (err) => {
13    if (err) console.error(err);
14    console.log('server listening on 3000');
15  });
16} else {
17  // required as a module => executed on aws lambda
18  exports.handler = awsLambdaFastify(init())
19}

The directory structure should look like the following tree:

 1serverless-api
 2├── README.md
 3├── bin
 4│   └── serverless-api.ts
 5├── cdk.json
 6├── handler
 7│   └── index.ts
 8├── jest.config.js
 9├── lib
10│   └── serverless-api-stack.ts
11├── package-lock.json
12├── package.json
13├── test
14│   └── serverless-api.test.ts
15└── tsconfig.json

With this method, we are able to test locally without deploying to the cloud.

First, transpile the Typescript files to JavaScript:

1npm run build

Then execute the handler/index.js file with node:

1node handler/index.js

If you visit http://localhost:3000 in your browser, it should display:

1{
2    "hello": "world"
3}

Deploying the function with the function url enabled

Fortunately, the AWS CDK enables users to quickly deploy using the NodeJSFunction construct. Replace the contents of serverless-api-stack.ts with the following snippet:

 1import * as cdk from 'aws-cdk-lib';
 2import { Construct } from 'constructs';
 3import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
 4import { FunctionUrlAuthType } from 'aws-cdk-lib/aws-lambda';
 5
 6export class ServerlessApiStack extends cdk.Stack {
 7  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
 8    super(scope, id, props);
 9    const handler = new NodejsFunction(this, 'handler', {
10      entry: './handler/index.ts',
11      timeout: cdk.Duration.minutes(1)
12    });
13    const url = handler.addFunctionUrl({
14      authType: FunctionUrlAuthType.NONE
15    });
16    new cdk.CfnOutput(this, 'url', {
17      value: url.url
18    });
19  }
20}

The code creates a NodejsFunction lambda, enables the function url without authentication, and outputs the url as a CloudFormation export.

Deploy the stack using the cdk:

1npx cdk deploy

The command output contains the CfnOutput value:

Do you wish to deploy these changes (y/n)? y
ServerlessApiStack: deploying... [1/1]
ServerlessApiStack: creating CloudFormation changeset...

 ✅  ServerlessApiStack

✨  Deployment time: 38.19s

Outputs:
ServerlessApiStack.url = https://{id}.lambda-url.us-east-1.on.aws/
Stack ARN:
arn:aws:cloudformation:us-east-1:123456789012:stack/ServerlessApiStack/{id}

If you navigate to the url, you will view the expected results displayed:

1{
2    "hello": "world"
3}

All of this was completed with very little infrastructure to manage and a single index.ts file. From here, you can expand the project to include as many routes as you prefer.

#typescript   #aws   #aws-cdk   #serverless  

Reply to this post by email ↪