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
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
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
To setup, run the serverless command
serverless
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
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.
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
Connect our handler to express
install aws-serverless-express
To install this, run this command:
npm i aws-serverless-express
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
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;
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);
}
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
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
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;
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
});
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,
}
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');
and then add it as a middleware for our app:
app.use('/user', userRoutes)
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
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.
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
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;
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' });
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
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
};
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);
});
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:
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
};
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.
Top comments (0)