DEV Community

Cover image for Build a backend API with Serverless, AWS, Express, and Fauna
uma victor
uma victor

Posted on

Build a backend API with Serverless, AWS, Express, and Fauna

Serverless can mean a variety of things, depending on the context, ranging from 3rd party libraries like Netlify to frameworks for creating serverless applications. This tutorial guides us on how we can build an API with AWS and serverless using express, modify it to fetch data the store the generated data in Fauna.

Goals

In this tutorial, we will look at how to create an express REST API using the serverless approach with AWS lambda and the Serverless CLI. Creating and managing our handlers. We will also learn how to store the data generated by our API in a database and read the data.

Prerequisites

To follow along in this tutorial, you need

  • Little knowledge of node
  • AWS account
  • Serverless CLI
  • node.js

Setting up our Project

For this tutorial, we will be building our backend API using NodeJS in the Command-Line-Interface. To begin our project, we will create the directory we will be using.
In our command line, we create our directory structure:

mkdir serverless && cd serverless
Enter fullscreen mode Exit fullscreen mode

Here we created a directory called serverless and entered this directory. We will then create a package.json file by running the npm initialization command

npm init
Enter fullscreen mode Exit fullscreen mode

When this is done, notice that a new file package.json which holds meta-data related to our project has been added to our directory.

Setup Serverless

Serverless refers to a method of providing backend services based on usage requirements. In this tutorial, we will use Serverless to manage our project, deploy, and manage resources along with AWS.
To install Serverless, input the following command:

npm install -g serverless
Enter fullscreen mode Exit fullscreen mode

To setup, run the serverless command

serverless
Enter fullscreen mode Exit fullscreen mode

This command sets up the required backend service for our API. Select AWS Node.js and enter the application name.

Setup AWS Node.js

Upon completion of the previous step, the aws-node template is downloaded and we get a prompt requesting us to login/register to Serverless dashboard. Select yes and follow the process to create a new account if you do not have one. After this, return to the CLI and select local AWS access key then proceed to create the account to get this key.

Create AWS account

We have a link opened up in our browser where you can create an AWS account and generate the needed credentials. Here we follow the steps for account creation to set up your user account.

Get AWS credentials

You can now proceed to add your credentials to the command line. These keys can be found under the security credentials of our user account. Here, we click on create new access key

Generating access key

You can find the keys in the pop up that appears by clicking on the show access key. Copy and paste these into your command line.

getting access credentials

Select yes to deploy the project. Move all generated serverless files from the created directory to the root directory and delete the empty folder.

Deploy all resources (lambda functions)

Open the project directory in your code editor. In the directory within the serverless file created for us, we find a file named serverless.yml that contains a function called hello and a handler, handler.hello. Navigate to handler.js we notice a function called hello is exported which takes an event and returns a response.
On our browser, on the AWS console page, search for Lamba in the service search bar. In it, we find the exported function hello

lambda function

Connect our handler to express

install aws-serverless-express

To install this, run this command:

npm i aws-serverless-express
Enter fullscreen mode Exit fullscreen mode

Other dependencies

For this tutorial we would require Express.js and other packages. We will install them using CLI:

npm i express body-parser cors
Enter fullscreen mode Exit fullscreen mode

We would then create a new folder in our root folder called src. This will be where all our express codes will be stored.

Initialize the Express handler

Create a file in the src folder called index.js to be the root file for the express app. Add the following code to the index.js to initialize our app

const express = require('express');
const app = express();
module.exports = app;
Enter fullscreen mode Exit fullscreen mode

Modify the Serverless file

First, we will clear all the code within the handler.js file and replace it with the following code:

const awsServerlessExpress = require('aws-serverless-express');
const app = require('./src/index');

const server = awsServerlessExpress.createServer(app);

module.handler = (event, context) => {
  return awsServerlessExpress.proxy(server, event, context);
}
Enter fullscreen mode Exit fullscreen mode

Here, we have made imports for aws-serverless-express and our app from index.js. We created a const named server to create our server. We then modified the handler function to return certain parameters.
Navigate to the serverless.yml file and here we will change the name of the function to something more descriptive, then change the name of the handler to the name of the function we exported above which is handler:

functions:
  app-api:
    handler: handler.handler
Enter fullscreen mode Exit fullscreen mode

Next, we will set events the function will respond to. To do this, add the following code to your functions file.

events:
      http:
        - http:
          path: /
          method: get
          cors: true
      - http:
          path: /{proxy+}
          method: any
          cors: true
Enter fullscreen mode Exit fullscreen mode

These events for the app-api function are set up to respond to any requests that get sent to it. It acts as a proxy based on the specified method first on the root path and then any other URL structure dependent on the API.
We will now proceed to modify our index.js file:

const bodyParser = require('body-parser');
const express = require('express');
const cors = require('cors')
const app = express();
app.use(cors());
app.use(bodyParser.json());
module.exports = app;
Enter fullscreen mode Exit fullscreen mode

We have added imports for extra dependencies and use these dependencies as middleware on the response that is returned to app.

Setup our Route

We will create a folder called routes within our src directory. Inside it, create a file called routes.js. Populate this file with the following code:

const express = require('express');
const routes = express.Router({
    mergeParams: true
});
Enter fullscreen mode Exit fullscreen mode

In the code above, we created a const called routes which takes in an object value. The mergeParams property is used to set up a child router to prevent having to specify the full route when responding to a request but can append as many routes as required to the existing child route.

Create a simple get route

To set up this route, add the following code to the routes.js file:

routes.get('/', (req, res) => {
    res.status(200).json({});
})
module.exports = {
    routes,
}
Enter fullscreen mode Exit fullscreen mode

Here, we created a route with a get method and a root path. There is a second parameter which is a callback function that takes two parameters req and res provided by express. This provides information on incoming requests. We send back an empty status of 200 and an empty array whenever the router is hit.
Finally, we will add this created route to our index.js:

const {
    routes: userRoutes,
} = require('./routes/routes');
Enter fullscreen mode Exit fullscreen mode

and then add it as a middleware for our app:

app.use('/user', userRoutes)
Enter fullscreen mode Exit fullscreen mode

What this does is that any path that has /user is automatically handled by userRoutes. You can now deploy your project in CLI by navigating to the folder containing serverless.yml and typing:

sls deploy
Enter fullscreen mode Exit fullscreen mode

Test our route with postman

After deploying, you will have an output in your CLI similar to the image below:

Copy the URL from the GET method, open postman and click on new http request. paste the URL and add /user at the end to make the request use the route we defined. Click on send request. The result will be a status code of 200 and an empty array.

Postman

Congrats, you just built an API. In modern applications where API’s are used to fetch large quantities of data, rather than simply returning the data to JSON, it is better practice to store this data in a database. This eases easy accessibility, arrangement and management of the data, and erases the need to run a new fetch request whenever the data is required as it is stored in a database. We will use Fauna a serverless real-time database to show how we can store and read data from our API. One major perk of Fauna is that it is easy to adopt and also easily accesible via API’s.

Fauna installation

To install Fauna in the CLI, use the commands below:

npm install --save faunadb
Enter fullscreen mode Exit fullscreen mode

After installation, we can initialize it by adding the following code at the top of our routes.js file:

var faunadb = require('faunadb')
var q = faunadb.query;
Enter fullscreen mode Exit fullscreen mode

The fauna.query module contains the functions we would require to create Fauna queries. Next, we would require an Admin key to access our Fauna database. First create an account on Fauna, create a database with a name of your choice, then on the dashboard click on security and create a new key.

Here, I’ve created a database named backendapi. Click on save and copy the key displayed on the page that opens next to your route.js file.

const client = new faunadb.Client({ secret: 'YOUR_FAUNADB_ADMIN_SECRET' });
Enter fullscreen mode Exit fullscreen mode

We will also create a collection to store our data in and an index to reference the collection.

Then we create the index to reference the collection:

We will modify our API to fetch news from NewsAPI. Create an API key and create your request by modifying the routes. Before that, we would need the node fetch module to perform fetch requests to get data from the news API. We will install this via CLI:

npm install node-fetch
Enter fullscreen mode Exit fullscreen mode

After installation, we can import it into our routes.js file and also export it so that it will be added when we deploy to Serverless.

const fetch = require("node-fetch");
//routes here
module.exports = {
  routes,
  fetch
};
Enter fullscreen mode Exit fullscreen mode

Then to fetch the news from NewsAPI we modify the routes:

routes.get("/", async (req, res) => {
   const response = await fetch(
     "https://newsapi.org/v2/top-headlines?sources=techcrunch&pageSize=1&apiKey=your API key"
   );
  const news = await response.json();
  res.status(200).json(news);
});
Enter fullscreen mode Exit fullscreen mode

In the request, I have set the value of pageSize to 1 to return only one result. If you run sls deploy to deploy to Serverless, and run API testing on the link. We get the result:

news fetch added

We will now modify the code to create a collection in our database and add the values of the article title and author from the request to our database. The finished code in routes will look like this:

var faunadb = require("faunadb");
const express = require("express");
const app = express();
const fetch = require("node-fetch");
const routes = express.Router({
  mergeParams: true,
});
const getreq = async () => {
  const client = new faunadb.Client({
    secret: "your Fauna secret",
  });
  const q = faunadb.query;
  try {
    const response = await fetch(
      "https://newsapi.org/v2/top-headlines?sources=techcrunch&pageSize=1&apiKey=your API key here"
    );
    const news = await response.json();
    await client.query(
      q.Create(q.Collection("news"), {
        data: { title:await news.articles[0].title, author:await news.articles[0].author },
      })
    );
    const document = await client.query(q.Get(q.Match(q.Index("news_index"))));
    return {
      statusCode: 200,
      body: {
        snippet: document.data,
      },
    };
  } catch (error) {
    res.status(400).json(error);
  }
}
routes.get("/", async (req, res) => {
   const info = await getreq();
   res.status(200).json(await info);
});
module.exports = {
  routes,
  fetch,
  faunadb
};
Enter fullscreen mode Exit fullscreen mode

Above, we created an async function getreq which we used to create the collection news with the data we got from the NewsAPI. We then referenced the news collection via the news_index index, got the data stored there and returned it. Now if you run sls deploy and run API testing on the URL you will get an image similar to the image below:

Also, if you check your collection in the Fauna database, you will also see the data from the API:

Conclusion

We have finally come to the end of this tutorial. Here, we covered how to create an express REST API using the serverless approach with AWS lambda and the serverless CLI. Creating and managing our handlers. Then we fetched data using the API and stored the data in a Fauna database.

Written in connection with the Write with Fauna Program.

Discussion (0)