Building Serverless REST APIs in AWS using Typescript KoaJS and the Serverless Framework

2022-09-18

While at Co.Lab, we wanted to train people looking propel their tech careers and in order to scale out our training we decided to build tools to reduce the amount of human effort required to facilitate our programs. Part of the tools we built was a collaborative learning platform where students could watch their pre-recorded lessons together (think Netflix watch parties but for education) complemented by collaborative documents for students to participate in lesson activities together. I like to use the term "synchronized lesson content delivery" to describe it.

While I was there, the technology stack for building our tools was:

  • Typescript as the programming language across backend and frontend
  • KoaJS as our web application framework
  • ReactJS for frontend development
  • DynamoDB for the database
  • AWS serverless architecture using AWS API Gateway & AWS Lambda
  • Serverless for configuration management

In this post, I'd like to briefly introduce you to the Serverless Architecture and how we built a serverless APIs with KoaJS and the Serverless Framework using AWS as our Cloud Service Provider.

Serverless Architecture

The Serverless architecture is a method of software application design that enables you build and run your applications without having to worry about managing software infrastructure. It takes away concerns such as what machines (physical or virtual) that the application will run on, how many they are and all the details involved with scaling it.

Cloud Service Providers usually provide services that enable developers build serverless applications. For example, Amazon Web Services (AWS) has AWS Lambda which is used in conjuction with Amazon API Gateway to provide serverless based web APIs. Google Cloud Platform (GCP) has Cloud Functions, Cloud Run and App Engine to enable developers build different types serverless computing workloads. Also, Microsoft Azure has Azure Functions as their serverless offering too. Serverless products offered by Cloud Service Providers are usually categorized as Function as a Service (Faas).S

Given that we're a young startup, it's important to be cost-effective with our design decisions. It's important to us that we don't consume more resources than we need but still be able to adapt and evolve to growing demand our services. Cloud Service Providers usually have a request-based cost model such that you're charged by the number of requests your services handle, taking into account the amount of time that your services use compute resources to handle the requests. serverless platforms do their best to spin up and down the compute resources you use so as to not add extra latency for your requests and so that you don't get charged when your service isn't doing anything.

Another great benefit with serverless architectures is the ability to detect increase in traffic and smoothly scale up resources to handle the increase. Say you have an ecommerce site for your small business and then you run a small promo on instagram for a Black Friday sale which gathers a lot of attention. If tons of people flock to your site, most serverless platforms can detect this and scale up to handle the increased traffic.

I've found though that as your service's load increases, there comes a point where it's just more cost effective to have a dedicated set of compute resources (servers, or nodes or pods depending on your underlying deployment model) running or in stand by to handle your requests. However, serverless is really great for bootstrapping applications and providing value quickly in a cost effective manner.

At the heart of the serverless architecture are serverless functions which is are pieces of ephemeral and stateless business logic software hosted on some managed infrastructure. The infrastructure providers take care of providing an interface to invoke these functions. They also take care of scalability concerns as the number of invocations of your function increases. Imagine you've built a whole javascript application with tons of important functions doing important business logic. Serverless architecture essentially enables you to deploy each of those functions as individual lightweight applications.

KoaJS

KoaJS is a node.js web framework built by the creators of express.js - the OG node.js web framework. It's really great for building web applications and APIs. It leverages the (async/await) functions rather than callbacks which encourages easier-to-follow code.

Serverless Framework

The Serverless framework provides an easy and open way to build serverless applications. It allows you to define your serverless infrastructure and all it's resources using a cloud service provider agnostic representation. The serverless framework makes it super easy to do CI/CD because once you've defined your applications serverless resources using the framework, deployments and updates are as easy as one CLI command.

For users of KoaJS with TypeScript, in this blog post, I'll introduce you to a serverless template to help you get up and running with a TypeScript KoaJS application for deployment AWS Lambda and exposed via AWS API Gateway.

When using the serverless framework with AWS, it leverages common AWS services to make your application accessible over the internet.

You can find the full template here. It leverages the serverless Typescript API to declare your serverless resources.

At the top level is the serverless.ts file which is the entry point for the serverless framework configuration.

import type { AWS } from '@serverless/typescript';

import api from '@functions/api';

const serverlessConfiguration: AWS = {
  service: 'aws-koajs-typescript-template',
  frameworkVersion: '2',
  custom: {
    webpack: {
      webpackConfig: './webpack.config.js',
      includeModules: true,
    },
  },
  plugins: [
    'serverless-webpack',
    'serverless-dotenv-plugin',
  ],
  provider: {
    name: 'aws',
    runtime: 'nodejs16.x',
    apiGateway: {
      minimumCompressionSize: 1024,
      shouldStartNameWithService: true,
    },
    environment: {
      AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1',
    },
    lambdaHashingVersion: '20201221',
  },
  // import the function via paths
  functions: { api },
};

module.exports = serverlessConfiguration;

The functions property outlines a set of serverless functions. In this approach we'll be deploying a while KoaJS Typescript application as a serverless function. So, the layout of our architecture will look like this:

image

The api function configuration looks like this:

import { handlerPath } from '@libs/handlerResolver';

export default {
  handler: `${handlerPath(__dirname)}/handler.main`,
  events: [
    {
      http: {
        method: 'ANY',
        // this matches the base path
        path: '/',
      },
    },
    {
      http: {
        method: 'ANY',
        // this matches any path, the token 'any' doesn't mean anything special
        path: '/{any+}',
      },
    },
  ],
}

This leverages the Typescript serverless API to define a function to handle all HTTP events. In AWS terms, this creates an AWS API Gateway endpoint that listenes to all HTTP events. These events are then passed to an AWS Lambda which will house your KoaJS application. This application will then handle the HTTP event accordingly.

The Serverless framework provides an API to convert AWS http events into requests that your KoaJS application can understand and handle. This API documentation can be found here. You can wrap your KoaJS server in a Serverless HTTP handler like so:

import ServerlessHttp from 'serverless-http';
import Koa from 'koa';

const app = new Koa();

// installation of your routes


export const main: ServerlessHttp.Handler = ServerlessHttp(app, {});

Feel free to take a deeper look at the template here. You can also make use of it in your next project.

First off, you'll need to install serverless. You can check out the serverless installation instructions here.

With that, you just need to run:

serverless create \
  --template-url https://github.com/jleoirab/serverless-aws-koajs-typescript-template
  --path my-service

And then, ensure to install all the npm dependencies:

cd my-service && npm i

That's it!