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 work.
For this part 2, we'll code the backend with Serverless Framework, and for parts 1 and 3:
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, allows us to send SMS for a phone number;
- Terraform: IaC (Infrastructure as Code) tool that allows 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 needed for these functions;
- NodeJS: JS runtime where our JavaScript lambda functions going to be running;
- JavaScript: Of course, the programming language we'll write our lambda.
Serverless Framework
The purpose of the 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
To create a project from a template for AWS + NodeJS, run on the terminal:
$ sls create --template aws-nodejs
Note the serverless.yml file. It's the configuration file of the service. Here we can also set resource provisions 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 the AWS Console like this:
Now let's deploy this to AWS running:
$ sls deploy
If everything is ok, we should see on the API Console the new resources /sms with a POST method.
We can test it with Postman ou directly on the 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 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 will implement authentication with Amazon Cognito: