How to create a REST API using AWS Lambda and API Gateway?

Serverless Architectures using AWS Lambda and other services provided by AWS like Amazon API Gateway are becoming popular when you don't want to have an overhead of maintaining the servers.

How to create a REST API using AWS Lambda and API Gateway?

Serverless Architectures using AWS Lambda and other services provided by AWS like Amazon API Gateway are becoming popular when you don't want to have an overhead of maintaining the servers. In one of the posts earlier, we talked about Ho you can use the Amazon API gateway and its service integration to Amazon DynamoDB to create an API for various processes.

In this post, we will talk about How can you create a Lambda function which will host your API created using Koajs and fronted by Amazon API Gateway. We will create a rest API with a proxy integration and when this API is called, it will invoke a Lambda function to fulfil the request. We will deploy the API Gateway and associated Lambda function using the AWS SAM.

Pre-requisites:

  • You should have access to an AWS account.
  • You should have some knowledge about stuff like API Gateway and AWS Lambda functions. If you are not aware of these things, I suggest you should go through some of the previous articles.

Repository:

All the code used in this post can be found in the GitHub repository here. You can use the repository as a barebone template to start creating your own API using the stack.

Directory Structure:

The following screenshot shows the directory structure for the project.

Directory Structure

The above directory structure has two folders.

  • src: For containing all the code
  • test: for containing all the test cases

The rest of the files are there for development and deployment purposes. We will look into the template file which will be used to deploy our solution on AWS using AWS SAM.

The directory structure for the src folder

The above structure is to organise our code. The following is the description for it.

  • middlewares: This folder will contain all our custom middlewares created for our APIs like logging middleware, etc. These will be hooked into the API and will run before or after our handler function is executed.
  • services: This folder contains all the route definitions and the handler function which needs to be executed for that specific route. This will isolate and divided the API into smaller parts which will be maintainable in the longer run.
  • app.js: This is the file that configures our app to be ready for receiving the request.
  • index.js: The entry point for our Lambda function.
  • server.js: The file to spin up the app locally for testing purposes.

Understanding Code

const {createServer, proxy} = require("aws-serverless-express");

const app = require("./app");

const server = createServer(app.callback());

exports.handler = (event, context) => proxy(server, event, context);
index.js

As mentioned above, the inde.js file will be used as an entry point for our AWS Lambda function. Every invokes of the Lambda function will receive event information which will include all the information we need to process the request. As we are using a proxy integration which means pass all the requests to the same Lambda function, we will use a package by AWS i.e. aws-serverless-express which converts the event to a request object for frameworks like express and koa.

We are using Koajs to configure ur API but you can use express as well. Let's see how to configure it using the koajs.

const Koa = require("koa");
const cors = require("@koa/cors");
const bodyparser = require("koa-bodyparser");
const mount = require("koa-mount");
const loggerMw = require("koa-mw-logger");

const middlewares = require("./middlewares");
const services = require("./services");

const app = new Koa();

app.use(cors());
app.use(bodyparser());
app.use(loggerMw());

/**
 * Mount all the middlewares on the umbrella app
 */
middlewares.forEach(mw => {
  app.use(mw);
});

/**
 * Mount all the services on the umbrella app
 */
services.forEach(svc => {
  app.use(mount(svc.path, svc.service));
});

module.exports = app;
app.js

The app.js file configures the koa app and makes it ready for the Lambda function to run when we receive the request. The middlewares from our folder and services from the services folder are configured and mounted on the koa app. Following is the code for handler.js and the index.js file for one of the sample services available in the repository.

async function handler(ctx, next) {
  // add handler logic here

  ctx.body = {"message": "Hello World"};
  return next();
}

module.exports = handler;
src/service/hello/handler.js

The handler.js file includes a function that will be executed when the route is called.

const Koa = require("koa");
const Router = require("@koa/router");

const handler = require("./handler");

const app = new Koa();
const router = new Router();

router.get("/hello", handler);

app
  .use(router.routes())
  .use(router.allowedMethods());

const plugin = {
  "path": "/api",
  "service": app
};

module.exports = plugin;
src/service/hello/index.js

This index file of the service is configuring the route and returning the small service with its configured app and the route on which this app needs to be mounted. The final result will be a route hosted on localhost will look like this http://localhost:8050/api/hello.

Deployment

We have looked into the parts of the code and understood how the directory and the code is structured for the same. Now we need to deploy it. We will do it using AWS SAM. Following is the template for the deployment.

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description:
  The barebone for aws lambda using koa and api gateway
Globals:
  Function:
    Timeout: 30
    Runtime: nodejs10.x
    MemorySize: 512
Resources:
  ApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      Name: API
      StageName: Test
      Cors:
        AllowMethods: "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
        AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
        AllowOrigin: "'*'"
  APIRoutes:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: "./src"
      Handler: index.handler
      Events:
        APIEvent:
          Type: Api
          Properties:
            RestApiId: !Ref ApiGateway
            Path: /{proxy+}
            Method: ANY
AWS SAM Template

If you are not familiar with how to understand AWS SAM templates, you can read the post here.

The above template will deploy the function and the API gateway defined in the resources section.

  • API Gateway resource will create an API gateway and set up the resources like the stage for further deployment. The cors policy will be set up as mentioned and also all the methods will be allowed as we are handling the methods in our Lambda function.
  • APIRoute resource is actually our Lambda function that will be deployed as part of this stack. The event section is what integrated the API Gateway and the AWS Lambda with each other. We are saying that whenever a request is made to API gateway, proxy everything to the Lambda function and we will take care of it.

Once deployment is complete, you can visit the API gate in your console and get an invoke URL to test it out.

Conclusion

This is one way to deploy the serverless API. The other way is to handle each route using a different Lambda function. I will be writing about that too in one of the upcoming posts. Also, there are things like authorization for API Gateway and having a friendly domain name rather than an invoke URL to use it. All these will come up in upcoming posts. Till then Happy Coding.

Subscribe to AWSMAG

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe