Vinícius A dos Santos

Vinícius A dos Santos

About Me
LinkedInGitHub

AWS API Gateway + Terraform + Serverless Framework - Part 2

javascript
nodejs
serverless
lambda
aws
aws api gateway
rest

Hi, everyone! For this "Hands on!" we're building a REST API with AWS API Gateway, provisioned with Terraform and backed by AWS Lambda built with Serverless Framework.
The REST API will allow us to send SMS Messages using AWS SNS. Sounds like a lot of things, but it's not that lot of working.
For this part 2, we'll code the backend with Serverless Framework and for part 1 and 3:

Part 1: provisioning an AWS API Gateway with Terraform
Part 3: securing the API with Amazon Cognito


About the tech stack

  • AWS: Most popular Cloud provider. You need an account to follow this article properly;
  • AWS API Gateway: AWS managed API Gateway that will expose our rest endpoints;
  • AWS Lambda: serverless functions on AWS working as our backend;
  • AWS SNS: AWS Simple Notification Service that, among other types of notifications, allow us to send SMS for a phone number;
  • Terraform: IaC (Infrastructure as Code) tool that allow us to provision cloud resources supporting several cloud providers;
  • Serverless Framework: a Framework for support building and deploying serverless functions grouped as a Serverless Service, allowing also the provisioning of resources need for these functions;
  • NodeJS: JS runtime where our JavaScript lambda functions going to be running;
  • JavaScript: Of course, the programing language we'll write our lambda.

Serverless Framework

The purpose of Serverless Framework is to provide a framework development, test, build, deploy and secure serverless applications, grouping functions in a service. Supporting several Cloud Providers as well.

Install it following instructions on https://www.serverless.com/framework/docs/getting-started and... Hands on!

Setting project

For create a project from a template for AWS + NodeJS, run on terminal:

$ sls create --template aws-nodejs

Note the serverless.yml file. It's the configuration file of the service. Here we can also set resources provision we might need as DynamoDB tables, SNS topics and so on. The file has a lot of commented lines, so let's clean it and leave it like this:

service: sms-sender-api

provider:
  name: aws
  runtime: nodejs12.x
  apiGateway:
    restApiId: wvnnv69jzf
    restApiRootResourceId: 0s0ivf
  region: us-east-1

functions: # defines a function (Lambda since AWS are our provider)
  hello:
    handler: handler.hello # JavaScript function that will handle the event generated for a call to this function
    events:
      - http: # We're defining that the function is triggered by an http call
          method: POST # the http method for the http call
          path: /sms # the api resource path

package:
  # excludes are added first
  exclude:
    - .vscode/**
    - .editorconfig
    - .terraform
    - terraform.*
    - .env
    - .env.**
    - .gitignore
    - .git
    - README.md
    - yarn.log
    - yarn.lock
    - package-lock.json
    - .prettierrc
    - .eslintrc.js

provider.apiGateway.restApiId and provider.apiGateway.restApiRootResourceId: references for the API and the resource path that should be a parent of any resource paths created by this service, respectively.
We can look for it on the API in AWS Console like this:

Now let's deploy this to AWS running:

$ sls deploy

If everything is ok, we should see on API Console the new resources /sms with a POST method.
We can test it with Postman ou directly on Console:

Once it's working, let's code the handler to send the SMS using Amazon SNS.
To do that, we need to start the NPM Package Manager and install the AWS SDK:

$ npm init && npm i aws-sdk --save

The handler.js file should be like this:

const AWS = require("aws-sdk");

module.exports.hello = async (event) => {
    AWS.config.update({ region: "us-east-1" });
    try {
        const { phoneNumber, message } = JSON.parse(event.body);
        await new AWS.SNS({ apiVersion: "2010-03-31" })
            .publish({ Message: message, PhoneNumber: `+55${phoneNumber}` })
            .promise();
        return {
            statusCode: 201,
            body: JSON.stringify(
                {
                    message: "SMS sent!",
                },
                null,
                2
            ),
        };
    } catch (error) {
        return {
            statusCode: 500,
            body: JSON.stringify(error),
        };
    }
};

The last thing is to allow the Lambda to access Amazon SNS changing serverless.yml:

# serverless.yml
...
provider:
  name: aws
  runtime: nodejs12.x
  apiGateway:
    restApiId: xxxxxxxx
    restApiRootResourceId: xxxxx
  region: us-east-1
  iamManagedPolicies:
    - 'arn:aws:iam::aws:policy/AmazonSNSFullAccess'...

Testing the api again, this time passing the JSON below, an SMS should be sent to the phone number.

{
    "phoneNumber": "11912345678",
    "message": "testing api"
}



That's it for this post. In part 3 we're implement authentication with Amazon Cognito:

Related Posts