Skip to content

Katarzyna Kmiotek

AWS Lambda in TypeScript with Terraform

Tutorial, AWS2 min read

AWS Lambda for years now supports NodeJS runtime and I was writing its code in JavaScript even if my language of choice in test automation would be TypeScript. It was safer to follow tutorials and use index.js as an entry point to my Lambdas I just had to make sure to have linter configured to catch my mistakes as early as possible and that I followed documentation (and its correct version).
Now I figured out how to write (and deploy) functions written in TypeScript and wanted to share my learnings.
I will be using Terraform - the module terraform-aws-modules/lambda/aws - makes tasks of managing and deploying Lambda much easier. The module itself is written in Python (in case you see any Python-related errors) and handles installing dependencies and zipping your fuction for you. Have you ever use pipline/workflow to zip your project? Or used provisioner "local-exec" to execute npm i and zip before deploying Lambda? If yes, you will appriciate this Terraform module.

TypeScript project

I will go through the steps of setting up the Lambda project as part of the Terraform IaC project (jump to Terraform if you want to skip this)

create src directory

1mkdir src && cd src/

intitatie new project (package manager of your choice)

1npm init -y

and update package.json of project related information - description, version, author etc

1touch index.ts

We will install two modules:
@types/aws-lambda This module will give us access to Lambda types in index.ts and TypeScript both as dev dependencies

1npm install -D typescript @types/aws-lambda

Installing npm modules - Lambda is a lightweight solution, its small size is emphasised also during Lambda upload and has a maximum size set to 50MB (can be overridden with layers if needed). That's why we install additional modules as devDependencies to avoid unnecessary size. You can always check the size of your project by running (Linux/MacOS) in the root of your project

1du -sh

setup TS config:

1npx tsc --init

this will create tsconfig.json file. AWS recommended config

1{
2 "compilerOptions": {
3 "target": "ES2016",
4 "strict": true,
5 "preserveConstEnums": true,
6 "noEmit": false,
7 "module":"commonjs",
8 "esModuleInterop": true,
9 "skipLibCheck": true,
10 "forceConsistentCasingInFileNames": true,
11 "isolatedModules": true,
12 },
13 "exclude": ["node_modules", "**/*.test.ts"]
14}

In the package.json add script:

1...
2"scripts": {
3 "build": "npx tsc",
4 },

And of course we need example code:

1import { Context, APIGatewayProxyCallback, APIGatewayEvent } from 'aws-lambda';
2
3export const handler = (event: APIGatewayEvent, context: Context, callback: APIGatewayProxyCallback): void => {
4 console.log(`Event: ${JSON.stringify(event, null, 2)}`);
5 console.log(`Context: ${JSON.stringify(context, null, 2)}`);
6 callback(null, {
7 statusCode: 200,
8 body: JSON.stringify({
9 message: 'hello world',
10 }),
11 });
12};

Terraform

In this section, I assume you already using Terraform and have the project configured with the AWS provider and your pipeline plans and apply Terraform to your AWS account.
Create TF file that will contain lambda definition

1touch lambda.tf

The basic configuartion of AWS Lambda module may look like this

1module "lambda_function" {
2 source = "terraform-aws-modules/lambda/aws"
3
4 function_name = "my-lambda"
5 description = "My awesome lambda function"
6 handler = "index.lambda_handler"
7 runtime = "python3.8"
8
9 source_path = "../src/lambda-function"
10
11 tags = {
12 Name = "my-lambda"
13 }
14}

Based on provided runtime and path to the function source module will install dependencies and zip project before uploading to AWS.
If we deploy it like this we could see an error in CloudWatch logs when try to execute this function: index.mjs has not been found. This is because we need to transpile TypeScript code to a JavaScript module and we can do it by running the previously set command npm run build
The Terraform Lambda module allows to override default runtime installing and zipping commands and we can provide them in a format like this:

1module "ts_lambda_function" {
2 source = "terraform-aws-modules/lambda/aws"
3
4 function_name = "ts-my-lambda"
5 description = "My lambda function written in TS"
6 handler = "index.handler"
7 runtime = "nodejs18.x"
8 source_path = [{
9 path = "../src"
10 commands = [
11 "npm ci", # install dependencies
12 "npm run build", # npx tsc to transpile
13 "npm prune --production"
14 ":zip" # zip all
15 ]
16 }]
17 publish = true
18
19 environment_variables = {
20 ENV = "dev"
21 }
22 attach_policy_statements = true
23 policy_statements = {
24 cloud_watch = {
25 effect = "Allow",
26 actions = ["cloudwatch:PutMetricData"],
27 resources = ["*"]
28 }
29 }
30 tags = {
31 Name = "ts-lambda"
32 }
33}

From here you can attach the desired trigger for the lambda, role etc.







Hope those few code snippets help with your project!

© 2024 by Katarzyna Kmiotek. All rights reserved.
Theme by LekoArts