Intro

TypeScript is a programming language which adds types to JavaScript. It allows to avoid many issues and find compilation errors beforehand. By using it you can definitely make your code much more readable, reliable and simplify your life (save a lot of your nerve cells). It can be used whenever you need to write JavaScript application and it is totally suitable to write code for AWS lambda. This article is about steps needed to write your aws lambda using TypeScript.

Steps to use TypeScript in aws lambda

Initiate aws lambda structure using SAM

SAM stands for Serverless Application Model and it’s an open source framework for building serverless applications (SAM github). We will use it for current example. The following command will start initiating our lambda.

sam init

Settings are pretty straightforward, but just in case you need them: sam init output

As a result the following structure will be created; folder's structure

Convert JavaScript into TypeScript

As you can see we have app.js file which contains actual code of initiated lambda function:

// const axios = require('axios')
// const url = 'http://checkip.amazonaws.com/';
let response;

/**
 *
 * Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
 * @param {Object} event - API Gateway Lambda Proxy Input Format
 *
 * Context doc: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html 
 * @param {Object} context
 *
 * Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
 * @returns {Object} object - API Gateway Lambda Proxy Output Format
 * 
 */
exports.lambdaHandler = async (event, context) => {
    try {
        // const ret = await axios(url);
        response = {
            'statusCode': 200,
            'body': JSON.stringify({
                message: 'hello world',
                // location: ret.data.trim()
            })
        }
    } catch (err) {
        console.log(err);
        return err;
    }

    return response
};

To convert JavaScript lambda into TypeScript lambda we need:

Step 1. Update package.json file

Add TypeScript compile script and needed devDependencies (@types/aws-lambda, @types/node, typescript) to package.json

{
  "name": "hello_world",
  "version": "1.0.0",
  "description": "hello world sample for NodeJS",
  "main": "app.js",
  "repository": "https://github.com/awslabs/aws-sam-cli/tree/develop/samcli/local/init/templates/cookiecutter-aws-sam-hello-nodejs",
  "author": "SAM CLI",
  "license": "MIT",
  "dependencies": {
    "axios": "^0.21.1"
  },
  "scripts": {
    "test": "mocha tests/unit/",
    "integ-test": "mocha tests/integration/",
    "compile": "tsc"
  },
  "devDependencies": {
    "aws-sdk": "^2.815.0",
    "chai": "^4.2.0",
    "mocha": "^8.2.1",
    "@types/aws-lambda": "^8.10.84",
    "@types/node": "^16.11.1",
    "typescript": "^4.4.4"
  }
}

Step 2. Create tsconfig.json (TypeScript configuration file)

{
  "compilerOptions": {
    "module": "CommonJS",
    "moduleResolution": "node",
    "outDir": "./build",
    "target": "ES2015"
  },
  "include": [
    "./*"
  ]
}

Where:

  • module - allows to use different modularization options. In this case CommonJS is used because aws runtime environment understands it without additional settings see docs
  • moduleResolution - defines strategy to locate modules. classic strategy did not work, that’s why node is used see docs
  • outDir - output directory where javascript files will eventually end up
  • target - specifies which language features will stay in output files see docs

Step 3. Convert js files into ts files

Apart from changing extension we will also change implementation to start using types

import {APIGatewayProxyEvent, Handler} from 'aws-lambda';

export const handler: Handler = async (event: APIGatewayProxyEvent) => {
    console.log(event);
    const response = {
        statusCode: 200,
        body: JSON.stringify(
            {
                message: 'Hi there javarubberduck',
                input: event,
            },
            null,
            2
        ),
    };
    return response
}

Now let’s check that everything compiles into JavaScript by running the following command

npm run compile

According to tsconfig.json file, our javascript files should appear in build folder.

Step 4. Update template.yaml file with new path to source code

Right now we need to let SAM know where to look for our JavaScript files, that’s why we need to update template.yaml

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: hello-world/build
      Handler: app.handler
      Runtime: nodejs12.x
      Events:
        HelloWorld:
          Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /hello
            Method: get

NOTE: Be aware that Handler property has to point to app.js file and function in it. If you named that function differently, you need to change this field correspondingly.

Deploy lambda and check it

sam deploy --guided

SAM will need correct AWS credentials to execute deployment. To check your lambda you can find your API gateway url in aws console or just check your output from sam deploy command.

Conclusion

TypeScript usage in aws lambda is very simple, but brings a lot of benefits to our developer’s life. In the next articles we will deploy TypeScript lambda using Serverless framework and built in SAM functionality

Updated: