Setting up TypeScript

In a previous blog I wrote about getting started with Serverless. We built a hello-world kind of app and deployed this to our Cloud Instance focusing on setting up the serverless yaml.

So now let’s have a look at setting up the development environment, with things like initializing npm and TypeScript on this project. We are starting with an npm init command in the command line. After answering some questions on the command line (or accepting the defaults) you should see a summary and hit enter (yes).

The main thing that happened, is that you now have a package.json file in your folder structure. So now we have a package.json and npm tools available. I like to also init TypeScript, since I prefer TypeScript over plain JavaScript on my projects. So first let’s install with npm i typescript. After installing TypeScript, we are running the init on the project with: tsc --init. This generates a tsconfig.json file.

After the two initialisations on the project, we see a couple of files have been added:

The tsconfig.json file is for configuration, for example let’s change something small here and set the outDir configured to ‘dist’. Now it is time to start using TypeScript instead of JavaScript. I also like to add a folder ‘src’ where my source files are. We move the handler.js to this folder and will change the extension from handler.js to .ts, in the message I added ‘Your typescript function executed successfully!‘ so we can see that it worked.

With the command tsc (TypeScript compile) you can compile your TypeScript code to a .js file. However, we would prefer to use the more common npm build command. To do this, we can add a build script in the package.json. In the scripts section we add: "build": "tsc". So now on the command line we can run npm run build.

This will run tsc and create a dist folder with the .js file.

Now remember that in the serverless.yml we have set the handler to handler.hello. We need to add the directory in front of this now, so this should be changed to dist/handler.hello.

To see if everything is still working correctly, we do an sls deploy to redeploy our serverless project to AWS. After this, we do a curl to the endpoint and get our success message:

Last but not least it is a good practice to ‘set up linting’. For this we start with installing eslint with npm i eslint, after which we do an npx eslint --init to initialize eslint on our project. The npx command makes sure you run the local library in your node_modules.

Answer the questions any way you like, above is just an example of what you can choose, but not necessarily a recommendation. So depending on the output you have selected, in this specific case I decided on JSON, a ‘.eslintrc.json’ file is added to the folder structure.

To run eslint on the whole project for all TypeScript files, you can use the command npx eslint src --ext .ts. But I’d rather put this in a script as well. So I add a script with the name eslint in the package.json. The beauty of putting this in the package.json is that we can now call the eslint from the build command as well, making sure when we build our code it is also linted. I changed the build script to "build": "tsc && npm run eslint". And now we can rerun an npm run build command.

This shows us 3 problems and the build fails! You can manually change some rules if you disagree, or you can change your code. To make the code compliant again, you can use the following:

module.exports.hello = async (event: any) => ({
  statusCode: 200,
  body: JSON.stringify(
    {
      message: 'Go Serverless v1.0! Your linted typescript function executed successfully!',
      input: event,
    },
    null,
    2,
  ),
});

Just to be totally sure everything works as expected, after the npm run build we can do an sls deploy again. Or if you like, you can create a deploy script within the package.json that runs sls deploy so you can run npm run deploy.

After this, we do another curl to the endpoint and we see the linted code has been deployed.

Getting started with Serverless Framework

While using the serverless stack from AWS, there are quite some tools out there to help you with the Infrastructure as Code part. In the end, we use CloudFormation to deploy our stacks, but there are multiple ways to create your CloudFormation template.

I have played around with SAM, CDK & Serverless Framework. The latter I used the most often, because it seems to be the weapon of choice by the majority of my clients. The plan is to write down a few blogs on tricks I learned while using the framework, no promise there though, for now, let’s begin with a “getting started”.

I write my Lambdas on AWS in Node.js, so the example code will be Node.js on AWS as well.
Through npm we can simply install Serverless:
npm install -g serverless

Now, simply running the serverless command, this will walk you through a couple of prompts. For now I will skip the monitor & test option and create a blog-examples project in AWS:

This creates a project structure with three files in it for you, a .gitignore, a handler.js, and a serverless.yml.

Basically, this is all you need. Personally, I prefer to switch to typescript, but for now, let’s have a closer look at the serverless.yml.

The serverless.yml is the main file concerning the Serverless Framework, in this YAML file you define your resources or point to other files where you have defined resources. On creation, there is a lot of documentation in the file, which can be helpful later on. The service is named after the project name and you can see that the provider is prefilled with aws and nodejs (12.x at the time of writing this).

If we scroll down, we hit a function. The function is called hello and it points the handler to handler.hello. For now that is all (besides the examples in the doc), a total of 5 key-value pairs in the YAML file.

Now, we want to override some of the defaults, to create our initial cf-stack. The following properties are already present in the serverless.yml, but still commented out with the default values attached to them. The stage I like to make explicit and the region I prefer to change to Frankfurt.

stage: dev
region: eu-central-1

Serverless uses an S3 bucket to upload the cf-templates and run the stack. I have created an S3 bucket manually on my AWS account, and I want to use this bucket instead of the default, so on the same level as the stage & region I added this bucket.

Now we are ready to go. If you want Serverless to create your CloudFormation templates, you can run the command serverless (sls) package:

This will now have created a .serverless folder in your folder structure. When you open the CloudFormation template, you might be surprised by what is created.

For this hello function, Serverless created the following resources:
– HelloLogGroup
– IamRoleLambdaExecution
– HelloLambdaFunction
– HelloLambdaVersion
It generated a LogGroup for the Lambda function, a default execution role, a function, and a versioned function. We will be able to install this correctly using the CloudFormation stack. However, to call it from the outside, we need an API Gateway as well.

We tell this to Serverless by adjusting the YAML file. After the handler we define an events property, telling Serverless this is an HTTP event, and enter a path and a method. This results in the following function defined in the YAML.

After this, we rerun the sls package command and have a look at the cf-template. We see that there are now some extra resources in the file to set up the API Gateway:
– ApiGatewayRestApi
– ApiGatewayResourceHello
– ApiGatewayMethodHelloGet
– ApiGatewayDeployment
– HelloLambdaPermissionApiGateway

Now, without going into the specifics, let’s run the deploy command (make sure you AWS user is up-to-date in your CLI) sls deploy.

Now, let’s have a closer look in the AWS console at what actually happens. We see that Serverless uploads the CloudFormation file to S3. Navigating into my S3 bucket, I indeed now see a folder serverless created.

After this it validates the stack and starts CloudFormation, so let’s have a look at CloudFormation in the console. Here, we now see the stack with status complete.

If we open it, we can now see the Stack Info, resources, output, etc., like we are used to with CloudFormation. Now let’s also take a look at the API Gateway in the AWS console.

Here we see the API Gateway resource is created, with the hello path as specified in the serverless.yml and with the HTTP method Get. We see it is set up as Lambda_proxy pointing to our Lambda function. Let’s click on the Lambda function to navigate to it and inspect this function as well.

Here we see our function in the designer, with an API Gateway trigger, and in the inline code we see the function code from our sources. So now there is only one final thing left to do, and that is: call the endpoint that has been given to us in the output. You can put this in your browser, or call it through curl. It should give us the message back, and the input.

So there you have it, easy to set up and to create CloudFormation templates. With just a few lines of YAML configuration, a CloudFormation template of almost 300 lines is generated.
Also notice how all our resources (the cf-stack, the Lambda function & the API Gateway) are prefixed with our stage (dev).

For more info and resources, check the Serverless website.