Deploying a TypeScript + Node AWS Lambda Function with Serverless
Serverless plugins make developing Lambda apps with TypeScript painless (no webpack required!)
This guide assumes you have TypeScript and Node installed as well as an AWS account. We'll be using serverless to set up our development environment and to package our app for deployment.
From mkdir
to Deploy
Let's get the boring stuff out of the way first. We'll install serverless and configure our AWS credentials. After that we're ready for our first deploy.
First, let's install the serverless CLI:
npm i serverless -g
We can now generate the minimum deployable boilerplate for our app:
mkdir node-typescript-lambda && cd node-typescript-lambda
serverless create --template aws-nodejs
We now have a simple Lambda function in handlers.js
and a serverless.yml
which will tell serverless how to deploy our function to AWS.
Now let's configure our AWS credentials so we can deploy our function. If you already have an access key and secret access key in ~/.aws/credentials then you can skip this step. First, sign in to the AWS console. At the top right, click on your name to toggle the dropdown and navigate to "My Security Credentials. Then on the left navigation pane, click on "Users" and select a user with appropriate access. Click on the "Security credentials tab" to bring up the pane we're interested in. Under the section "Access keys" click "Create Acccess key"
Take note of the two keys you've generated and then run the following command in your terminal, replacing YOUR_ACCESS_KEY
and YOUR_SECRET_KEY
with their actual values.
serverless config credentials --provider aws --key YOUR_ACCESS_KEY --secret YOUR_SECRET_KEY
You can now choose to deploy with serverless deploy
, but be warned this will count as a request made on your AWS account, and may incur a charge.
Serverless plugins
We're going to be using two serverless plugins. serverless-offline
will allow us to test changes to our app locally. serverless-plugin-typescript
will automatically compile our TypeScript files down to JavaScript both when we're developing locally and when we deploy our app.
To keep your deployment payload small, it's important to declare these plugins as dev dependencies, otherwise serverless will install them before deploying them, increasing your lambda function's size from <1kB to >30MB
npm init
npm i serverless-offline serverless-plugin-typescript --save-dev
We'll run our local environment with severless offline start
but first we we need to edit serverless.yml
to include the plugins we just installed.
Anywhere at the lowest indendation level in serverless.yml
include these lines.
plugins:
- serverless-plugin-typescript
- serverless-offline
If you were to remove serverless-plugin-typescript
you would be able to start your dev server, but we'll first need a tsconfig.json
to tell the TypeScript compiler what to do. While we're at it, let's install the type definitions for aws-lambda.
tsc --init
npm i @types/aws-lambda --save-dev
You can configure your tsconfig.json
to your personal preference, the only requirement is: "rootDir": "./"
so that the compiler knows to look for .ts
files in the current directory. If you choose to move all your .ts
files to a new folder called ./src
, for example, make sure to change the setting to "rootDir": "./src"
. You can also set "es6" as your compilation target because Lambda uses Node 6, which supports it. I've included a sample tsconfig.json
here:
Adding Types
Our handler.js
could use a makeover. Let's rename it to handlers.ts
and run our development server with serverless offline start
.
We'll first import the relevant types from 'aws-lambda'
and then add types to each of the function's parameters as well as the response
object.
import { Handler, Context, Callback } from 'aws-lambda';
interface HelloResponse {
statusCode: number;
body: string;
}
const hello: Handler = (event: any, context: Context, callback: Callback) => {
const response: HelloResponse = {
statusCode: 200,
body: JSON.stringify({
message: Math.floor(Math.random() * 10)
})
};
callback(undefined, response);
};
export { hello }
With these type definitions, our editor will loudly warn us when we try to add a key that shouldn't exist and provide suggestions based off the type definitions.
We're almost ready to deploy this test function, but first let's exclude node_modules from our serverless.yml
so we don't deploy aws-lambda
and all of its dependencies.
Anywhere at the lowest indendation level of serverless.yml
add the following lines:
package:
exclude:
- node_modules/**/*
include:
handler.ts
Making Our Lambda Function an Endpoint
By editing our serverless.yml once more, we can configure our Lambda function to be a visitable URL with AWS APIGateway.
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
By adding the last four lines, we configure our hello
Lambda function to expose the path /hello to an HTTP GET request. If we run serverless deploy
now it will generate a URL that you can visit in your browser.