Serverless APIs Full Guide - Part 1 (Hello World)

This is the first part of a series about how to build a serverless api in aws.

Cover image

Introduction

In case you don't know serverless is gaining popularity around the world in terms of software development due to its scalability, high availability and cost efficiency that makes it a solid option of architecture nowadays. Its entire framework is based on "pay what you use only when you use it" and that its accomplished thanks to the major cloud computing providers such as AWS. Serverless in a nutshell is a SaaS (software as a service) solution for developers who wants to take advantage of the benefits of using managed services such as I described above and it works for both, small teams that wants to save time of managing infrastructure and big ones that needs a high scalable solution. At this day there are serverless solutions for almost every piece of a robust software architecture including databases, computing, messaging, data streaming, notifications, logging, etc... and that can deliver a huge amount of competitive edge over a traditional architecture and even against a containerized one so I definitely recommend it.

In this series we're going to review how to work with serverless APIs applying concepts like unit testing, NoSQL, DevOps (CI/CD) and IaC (Infrastructure as Code) that hopefully it will help you to take that big step towards serverless.

Prerequisites

  • Node.js (recent version like 10 or above)
  • AWS Account
  • IAM User
  • AWS CLI installed

Hands On!

API

So let's get started and create a new directory and run npm init -y to start node.js (it basically should create the package.json file on your directory) then install the libraries needed first lets install serverless framework globally with npm i -g serverless, now the local dependencies npm i express serverless-http so our package.json should be looking something like:

{
  "name": "code",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1",
    "serverless-http": "^2.7.0"
  }
}

Now we go ahead to code our first method so lets create a js file named server.js first configure the express app by importing express and initiating it:

const express = require('express')

let app = express()

app.use(express.json())

After that we create a new method to handle GET requests into the base path and we're going to respond with a hello world message just to prove that everything it's running fine:

app.get('/', function(req, res) {
    res.send('Hello world')
})

Then we create a listen method to start the server properly in a port of our choice:

const PORT = 3000
app.listen(PORT, function() {
    console.log(`App listening on http://localhost:${PORT}`)
})

Finally we test our API with node server.js and in our localhost route should be returning the "Hello world" message and that's it for the methods by now.

Deployment

Now we're going to deploy the API to AWS so we need to first understand how the architecture will look like, the image below depicts how first the API Gateway service receives the request the client made and then proxy forwards to our express application running on lambda to handle the request and provide a response, that response will return first to API Gateway and then to the client.

Therefore we're going to setup our aws credentials you can obtain those credentials in AWS Console>IAM>Users>YOUR USER>Access Keys, so lets authorize our terminal to act in our behalf by setting up our security credentials running the command aws configure this command will prompt 4 things as it shown below:

AWS Access Key ID [********************]: 
AWS Secret Access Key [********************]: 
Default region name [us-east-1]: 
Default output format [json]: 

Once you filled the information we can continue to set up the deployment of our application so lets go ahead to our code to make a couple of adjustments, first in our server.js file we're going to add 2 lines of code, the first one to import serverless-http (const serverless = require('serverless-http')) and the second one to export our application as a serverless app (module.exports.handler = serverless(app)) and our file should be looking something like this:

const express = require('express')
const serverless = require('serverless-http')

let app = express()

app.use(express.json())

app.get('/', function(req, res) {
    res.send('Hello world')
})

const PORT = 3000
app.listen(PORT, function() {
    console.log(`App listening on http://localhost:${PORT}`)
})

module.exports.handler = serverless(app)

Then we're going to add a serverless template to describe the desired configuration for the deployment of our application to AWS, so lets create a new file called serverless.yml and write the following configuration:

service: API-Serverless-Series

provider:
  name: aws
  runtime: nodejs12.x
  memorySize: 128
  stage: dev
  region: us-east-1
functions:
  app:
    handler: server.handler
    events:
      - http: ANY /
      - http: 'ANY {proxy+}'

We're almost done, add a new script in our package.json to set up a serverless deployment command:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "deploy": "sls deploy"
  },

And finally run our new script npm run deploy it takes a couple of minutes but when it's done if everything is fine the output should be something like this:

Service Information
service: API-Serverless-Series
stage: dev
region: us-east-1
stack: API-Serverless-Series-dev
resources: 12
api keys:
  None
endpoints:
  ANY - https://88z63xjjxf.execute-api.us-east-1.amazonaws.com/dev
  ANY - https://88z63xjjxf.execute-api.us-east-1.amazonaws.com/dev/{proxy+}
functions:
  app: API-Serverless-Series-dev-app
layers:
  None

So lets click the first link and your application should be now running on AWS Lambda!

And that's it I hope it was helpful, see you in part 2!