How to build blazing fast REST APIs with Node.js, MongoDB, Fastify and Swagger

How to build blazing fast REST APIs with Node.js, MongoDB, Fastify and Swagger

Presumably no web developer is a stranger to REST APIs and the challenges that architecting an effective and efficient API solution brings...

Presumably no web developer is a stranger to REST APIs and the challenges that architecting an effective and efficient API solution brings...

These challenges include:
  • Speed (API Response Times)
  • Documentation (Clear concise documents, describing the API)
  • Architecture and Sustainability (Maintainable and expandable codebase)

In this tutorial we are going to address all of the above using a combination of Node.jsMongoDBFastify and Swagger.

The source code for the project is available on GitHub.

Before we begin…

You should have some beginner/intermediate JavaScript knowledge, have heard of Node.js and MongoDB, and know what REST APIs are.

Below are some links to get you updated:

  • Speed (API Response Times)
  • Documentation (Clear concise documents, describing the API)
  • Architecture and Sustainability (Maintainable and expandable codebase)

The Technology we will be using:

  • Speed (API Response Times)
  • Documentation (Clear concise documents, describing the API)
  • Architecture and Sustainability (Maintainable and expandable codebase)

It is a good idea to open the above pages in new tabs, for easy reference.

You will need to have the following installed:
  • Speed (API Response Times)
  • Documentation (Clear concise documents, describing the API)
  • Architecture and Sustainability (Maintainable and expandable codebase)

You will also need an IDE and a terminal, I use iTerm2 for Mac and Hyper for Windows.

Let’s get started!

Initialise a new project by opening your terminal, executing each of the following lines of code:

mkdir fastify-api
cd fastify-api
mkdir src
cd src
touch index.js
npm init

In the above code, we created two new directories, navigated into them, created an index.js file and initialed our project via npm.

You will be prompted to enter several values when initialising a new project, these you can leave blank and update at a later stage.

Once completed, a package.json file is generated in the src directory. In this file you can change the values entered when the project was initialised.

Next we install all the dependancies that we will need:

npm i nodemon mongoose fastify fastify-swagger boom

Below is a brief description of what each package does, quoted from their respective websites:

nodemon

nodemon is a tool that helps develop node.js based applications by automatically restarting the node application when file changes in the directory are detected.> nodemon is a tool that helps develop node.js based applications by automatically restarting the node application when file changes in the directory are detected.
To set up nodemon, we need to add the following line of code to our package.json file, in the scripts object:

“start”: “./node_modules/nodemon/bin/nodemon.js ./src/index.js”,

Our package.json file should now look as follows:

{
  "name": "fastify-api",
  "version": "1.0.0",
  "description": "A blazing fast REST APIs with Node.js, MongoDB, Fastify and Swagger.",
  "main": "index.js",
  "scripts": {
  "start": "./node_modules/nodemon/bin/nodemon.js ./src/index.js",
  "test": "echo \"Error: no test specified\" && exit 1"
},
  "author": "Siegfried Grimbeek <[email protected]> (www.siegfriedgrimbeek.co.za)",
  "license": "ISC",
  "dependencies": {
  "boom": "^7.2.2",
  "fastify": "^1.13.0",
  "fastify-swagger": "^0.15.3",
  "mongoose": "^5.3.14",
  "nodemon": "^1.18.7"
  }
}

mongoose

nodemon is a tool that helps develop node.js based applications by automatically restarting the node application when file changes in the directory are detected.
fastify
nodemon is a tool that helps develop node.js based applications by automatically restarting the node application when file changes in the directory are detected.
fastify-swagger
nodemon is a tool that helps develop node.js based applications by automatically restarting the node application when file changes in the directory are detected.
boom
nodemon is a tool that helps develop node.js based applications by automatically restarting the node application when file changes in the directory are detected.### Setup up the server and create the first route!

Add the following code to your index.js file:

// Require the framework and instantiate it
const fastify = require('fastify')({
  logger: true
})

// Declare a route
fastify.get('/', async (request, reply) => {
  return { hello: 'world' }
})

// Run the server!
const start = async () => {
  try {
    await fastify.listen(3000)
    fastify.log.info(`server listening on ${fastify.server.address().port}`)
  } catch (err) {
    fastify.log.error(err)
    process.exit(1)
  }
}
start()

We require the Fastify framework, declare our first route and initialise the server on port 3000, the code is pretty self explanatory but take note of the options object passed when initialising Fastify:

// Require the fastify framework and instantiate it
const fastify = require('fastify')({
  logger: true
})

The above code enables Fastify’s built in logger which is disabled by default.

You can now run the follow code in your src directory in your terminal:

npm start

Now when you navigate to http://localhost:3000/ you should see the {hello:world} object returned.

We will get back to the index.js file but for now let’s move on to setting up our database.

Start MongoDB and create the model!

Once MongoDB has been successfully installed, you can open a new terminal window and start up a MongoDBinstance by running the following:

mongod

With MongoDB, we do not need to create a database. We can just specify a name in the setup and as soon as we store data, MongoDB will create this database for us.

Add the following to your index.js file:

...
// Require external modules
const mongoose = require('mongoose')
// Connect to DB
mongoose.connect(‘mongodb://localhost/mycargarage’)
 .then(() => console.log(‘MongoDB connected…’))
 .catch(err => console.log(err))
...

In the above code we require Mongoose and connect to our MongoDB database. The database is called mycargarage and if all went well, you will now see MongoDB connected... in your terminal.

Notice that you did not have to restart the app, thanks to the _Nodemon_ package that we added earlier.

Now that our database is up and running, we can create our first Model. Create a new folder within the src directory called models, and within it create a new file called Car.js and add the following code:

// External Dependancies
const mongoose = require('mongoose')

const carSchema = new mongoose.Schema({
  title: String,
  brand: String,
  price: String,
  age: Number,
  services: {
    type: Map,
    of: String
  }
})

module.exports = mongoose.model('Car', carSchema)

The above code declares our carSchema that contains all the information related to our cars. Apart from the two obvious data types: String and Number. We also make use of a Map which is relatively new to Mongoose and you can read more about it here. We then export our carSchema to be used within our app.

We could proceed with setting up our routes, controllers and config in the index.js file, but part of this tutorial is demonstrating a sustainable codebase. Therefore each component will have its own folder.

Create the car controller

To get started with creating the controllers, we create a folder in the src directory called controllers, and within the folder, we create a carController.js file:

// External Dependancies
const boom = require('boom')

// Get Data Models
const Car = require('../models/Car')

// Get all cars
exports.getCars = async (req, reply) => {
  try {
    const cars = await Car.find()
    return cars
  } catch (err) {
    throw boom.boomify(err)
  }
}

// Get single car by ID
exports.getSingleCar = async (req, reply) => {
  try {
    const id = req.params.id
    const car = await Car.findById(id)
    return car
  } catch (err) {
    throw boom.boomify(err)
  }
}

// Add a new car
exports.addCar = async (req, reply) => {
  try {
    const car = new Car(req.body)
    return car.save()
  } catch (err) {
    throw boom.boomify(err)
  }
}

// Update an existing car
exports.updateCar = async (req, reply) => {
  try {
    const id = req.params.id
    const car = req.body
    const { ...updateData } = car
    const update = await Car.findByIdAndUpdate(id, updateData, { new: true })
    return update
  } catch (err) {
    throw boom.boomify(err)
  }
}

// Delete a car
exports.deleteCar = async (req, reply) => {
  try {
    const id = req.params.id
    const car = await Car.findByIdAndRemove(id)
    return car
  } catch (err) {
    throw boom.boomify(err)
  }
}

The above may seem like a little much to take in, but it is actually really simple.

  • Speed (API Response Times)
  • Documentation (Clear concise documents, describing the API)
  • Architecture and Sustainability (Maintainable and expandable codebase)

Other than that, we make use of some standard Mongoose features used to manipulate our database.

You are probably burning to fire up your API and do a sanity check, but before we do this, we just need to connect the controller to the routes and then lastly connect the routes to the app.

Create and import the routes

Once again, we can start by creating a folder in the root directory of our project, but this time, it is called routes. Within the folder, we create an index.js file with the following code:

// Import our Controllers
const carController = require('../controllers/carController')

const routes = [
  {
    method: 'GET',
    url: '/api/cars',
    handler: carController.getCars
  },
  {
    method: 'GET',
    url: '/api/cars/:id',
    handler: carController.getSingleCar
  },
  {
    method: 'POST',
    url: '/api/cars',
    handler: carController.addCar,
    schema: documentation.addCarSchema
  },
  {
    method: 'PUT',
    url: '/api/cars/:id',
    handler: carController.updateCar
  },
  {
    method: 'DELETE',
    url: '/api/cars/:id',
    handler: carController.deleteCar
  }
]

module.exports = routes

Here we are requiring our controller and assigning each of the functions that we created in our controller to our routes.

As you can see, each route consists out of a method, a url and a handler, instructing the app on which function to use when one of the routes is accessed.

The :id following some of the routes is a common way to pass parameters to the routes, and this will allow us to access the id as follows:

[[http://127.0.0.1:3000/api/cars/5bfe30b46fe410e1cfff2323](http://127.0.0.1:3000/api/cars/5bfe30b46fe410e1cfff2323)](http://127.0.0.1:3000/api/cars/5bfe30b46fe410e1cfff2323](http://127.0.0.1:3000/api/cars/5bfe30b46fe410e1cfff2323) "http://127.0.0.1:3000/api/cars/5bfe30b46fe410e1cfff2323](http://127.0.0.1:3000/api/cars/5bfe30b46fe410e1cfff2323)")

Putting it all together and testing our API

Now that we have most of our parts constructed, we just need to connect them all together to start serving data via our API. Firstly we need to import our routes that we created by adding the following line of code to our main index.js file:

const routes = require(‘./routes’)

We then need to loop over our routes array to initialise them with Fastify. We can do this with the following code, which also needs to be added to the main index.js file:

routes.forEach((route, index) => {
 fastify.route(route)
})

Now we are ready to start testing!

The best tool for the job is Postman, which we will use to test all of our routes. We will be sending our data as raw objects in the body of the request and as parameters.

Finding all cars:

Finding a single car:

Adding a new car**:

** The services appear to be empty, but the information does in fact persist to the database.

Updating a car:

Deleting a car:

We now have a fully functional API — but what about the documentation? This is where Swagger is really handy.

Adding Swagger and wrapping up.

Now we will create our final folder called config. Inside we will create a file called swagger.js with the following code:

exports.options = {
  routePrefix: '/documentation',
  exposeRoute: true,
  swagger: {
    info: {
      title: 'Fastify API',
      description: 'Building a blazing fast REST API with Node.js, MongoDB, Fastify and Swagger',
      version: '1.0.0'
    },
    externalDocs: {
      url: 'https://swagger.io',
      description: 'Find more info here'
    },
    host: 'localhost',
    schemes: ['http'],
    consumes: ['application/json'],
    produces: ['application/json']
  }
}

The above code is an object with the options which we will pass into our fastify-swagger plugin. To do this, we need to add the following to our index.js file:

// Import Swagger Options
const swagger = require(‘./config/swagger’)
// Register Swagger
fastify.register(require(‘fastify-swagger’), swagger.options)

And then we need to add the following line after we have initialised our Fastify server:

...
await fastify.listen(3000)
fastify.swagger()
fastify.log.info(`listening on ${fastify.server.address().port}`)
...

And that is it! If you now navigate to http://localhost:3000/documentation, you should see the following:

As simple as that! You now have self updating API documentation that will evolve with your API. You can easily add additional information to your routes, see more here.

Whats Next?

Now that we have a basic API in place, the possibilities are limitless. It can be used as the base for any app imaginable.

In the next tutorial, we will integrate GraphQL and eventually integrate the frontend with Vue.js too!

Learn More

☞ The Complete Node.js Developer Course (2nd Edition)

☞ Learn and Understand NodeJS

☞ Node JS: Advanced Concepts

☞ GraphQL: Learning GraphQL with Node.Js

☞ Angular (Angular 2+) & NodeJS - The MEAN Stack Guide

How to Build a RESTful API in Node.js, Express.js & MongoDB (Mongoose)

How to Build a RESTful API in Node.js, Express.js & MongoDB (Mongoose)

How to Build a RESTful API in Node.js, Express.js and MongoDB (Mongoose). Learn to create your first RESTful API in NodeJS, ExpressJS, and MongoDB (mongoose). We cover the MVC pattern, CRUD, Routes, Error Handling, ES6, Promises, GET, POST, DELETE in under 50 minutes. Learn to build a REST API to create,modify and delete users in a database. Build a simple API using ExpressJs and MongoDb with CRUD functions for Contacts.

How to Build a RESTful API in Node.js, Express.js & MongoDB (Mongoose)

Learn to create your first RESTful API in NodeJS, ExpressJS, and MongoDB (mongoose).

We cover the MVC pattern, CRUD, Routes, Error Handling, ES6, Promises, GET, POST, DELETE in under 50 minutes. Learn to build a REST API to create,modify and delete users in a database. Build a simple API using ExpressJs and MongoDb with CRUD functions for Contacts.

Build a REST API using Node.js, Express.js, Mongoose.js and MongoDB

Build a REST API using Node.js, Express.js, Mongoose.js and MongoDB

Node.js, Express.js, Mongoose.js, and MongoDB is a great combination for building easy and fast REST API. You will see how fast that combination than other existing frameworks because of Node.js is a packaged compilation of Google’s V8 JavaScript engine and it works on non-blocking and event-driven I/O. Express.js is a Javascript web server that has a complete function of web development including REST API.

Node.js, Express.js, Mongoose.js, and MongoDB is a great combination for building easy and fast REST API. You will see how fast that combination than other existing frameworks because of Node.js is a packaged compilation of Google’s V8 JavaScript engine and it works on non-blocking and event-driven I/O. Express.js is a Javascript web server that has a complete function of web development including REST API.

This tutorial divided into several steps:

Step #1. Create Express.js Application and Install Required Modules
Step #2. Add Mongoose.js Module as ORM for MongoDB
Step #3. Create Product Mongoose Model
Step #4. Create Routes for the REST API endpoint
Step #5. Test REST API Endpoints

Source codes here:
https://github.com/didinj/NodeRestApi...

How to Use Express.js, Node.js and MongoDB.js

How to Use Express.js, Node.js and MongoDB.js

In this post, I will show you how to use Express.js, Node.js and MongoDB.js. We will be creating a very simple Node application, that will allow users to input data that they want to store in a MongoDB database. It will also show all items that have been entered into the database.

In this post, I will show you how to use Express.js, Node.js and MongoDB.js. We will be creating a very simple Node application, that will allow users to input data that they want to store in a MongoDB database. It will also show all items that have been entered into the database.

Creating a Node Application

To get started I would recommend creating a new database that will contain our application. For this demo I am creating a directory called node-demo. After creating the directory you will need to change into that directory.

mkdir node-demo
cd node-demo

Once we are in the directory we will need to create an application and we can do this by running the command
npm init

This will ask you a series of questions. Here are the answers I gave to the prompts.

The first step is to create a file that will contain our code for our Node.js server.

touch app.js

In our app.js we are going to add the following code to build a very simple Node.js Application.

var express = require("express");
var app = express();
var port = 3000;
 
app.get("/", (req, res) => {
&nbsp;&nbsp;res.send("Hello World");
});
 
app.listen(port, () => {
  console.log("Server listening on port " + port);
});

What the code does is require the express.js application. It then creates app by calling express. We define our port to be 3000.

The app.use line will listen to requests from the browser and will return the text “Hello World” back to the browser.

The last line actually starts the server and tells it to listen on port 3000.

Installing Express

Our app.js required the Express.js module. We need to install express in order for this to work properly. Go to your terminal and enter this command.

npm install express --save

This command will install the express module into our package.json. The module is installed as a dependency in our package.json as shown below.

To test our application you can go to the terminal and enter the command

node app.js

Open up a browser and navigate to the url http://localhost:3000

You will see the following in your browser

Creating Website to Save Data to MongoDB Database

Instead of showing the text “Hello World” when people view your application, what we want to do is to show a place for user to save data to the database.

We are going to allow users to enter a first name and a last name that we will be saving in the database.

To do this we will need to create a basic HTML file. In your terminal enter the following command to create an index.html file.

touch index.html

In our index.html file we will be creating an input filed where users can input data that they want to have stored in the database. We will also need a button for users to click on that will add the data to the database.

Here is what our index.html file looks like.

<!DOCTYPE html>
<html>
  <head>
    <title>Intro to Node and MongoDB<title>
  <head>

  <body>
    <h1>Into to Node and MongoDB<&#47;h1>
    <form method="post" action="/addname">
      <label>Enter Your Name<&#47;label><br>
      <input type="text" name="firstName" placeholder="Enter first name..." required>
      <input type="text" name="lastName" placeholder="Enter last name..." required>
      <input type="submit" value="Add Name">
    </form>
  <body>
<html>

If you are familiar with HTML, you will not find anything unusual in our code for our index.html file. We are creating a form where users can input their first name and last name and then click an “Add Name” button.

The form will do a post call to the /addname endpoint. We will be talking about endpoints and post later in this tutorial.

Displaying our Website to Users

We were previously displaying the text “Hello World” to users when they visited our website. Now we want to display our html file that we created. To do this we will need to change the app.use line our our app.js file.

We will be using the sendFile command to show the index.html file. We will need to tell the server exactly where to find the index.html file. We can do that by using a node global call __dirname. The __dirname will provide the current directly where the command was run. We will then append the path to our index.html file.

The app.use lines will need to be changed to
app.use("/", (req, res) => {   res.sendFile(__dirname + "/index.html"); });

Once you have saved your app.js file, we can test it by going to terminal and running node app.js

Open your browser and navigate to “http://localhost:3000”. You will see the following

Connecting to the Database

Now we need to add our database to the application. We will be connecting to a MongoDB database. I am assuming that you already have MongoDB installed and running on your computer.

To connect to the MongoDB database we are going to use a module called Mongoose. We will need to install mongoose module just like we did with express. Go to your terminal and enter the following command.
npm install mongoose --save

This will install the mongoose model and add it as a dependency in our package.json.

Connecting to the Database

Now that we have the mongoose module installed, we need to connect to the database in our app.js file. MongoDB, by default, runs on port 27017. You connect to the database by telling it the location of the database and the name of the database.

In our app.js file after the line for the port and before the app.use line, enter the following two lines to get access to mongoose and to connect to the database. For the database, I am going to use “node-demo”.

var mongoose = require("mongoose"); mongoose.Promise = global.Promise; mongoose.connect("mongodb://localhost:27017/node-demo");

Creating a Database Schema

Once the user enters data in the input field and clicks the add button, we want the contents of the input field to be stored in the database. In order to know the format of the data in the database, we need to have a Schema.

For this tutorial, we will need a very simple Schema that has only two fields. I am going to call the field firstName and lastName. The data stored in both fields will be a String.

After connecting to the database in our app.js we need to define our Schema. Here are the lines you need to add to the app.js.
var nameSchema = new mongoose.Schema({   firstName: String,   lastNameName: String });

Once we have built our Schema, we need to create a model from it. I am going to call my model “DataInput”. Here is the line you will add next to create our mode.
var User = mongoose.model("User", nameSchema);

Creating RESTful API

Now that we have a connection to our database, we need to create the mechanism by which data will be added to the database. This is done through our REST API. We will need to create an endpoint that will be used to send data to our server. Once the server receives this data then it will store the data in the database.

An endpoint is a route that our server will be listening to to get data from the browser. We already have one route that we have created already in the application and that is the route that is listening at the endpoint “/” which is the homepage of our application.

HTTP Verbs in a REST API

The communication between the client(the browser) and the server is done through an HTTP verb. The most common HTTP verbs are
GET, PUT, POST, and DELETE.

The following table explains what each HTTP verb does.

HTTP Verb Operation
GET Read
POST Create
PUT Update
DELETE Delete

As you can see from these verbs, they form the basis of CRUD operations that I talked about previously.

Building a CRUD endpoint

If you remember, the form in our index.html file used a post method to call this endpoint. We will now create this endpoint.

In our previous endpoint we used a “GET” http verb to display the index.html file. We are going to do something very similar but instead of using “GET”, we are going to use “POST”. To get started this is what the framework of our endpoint will look like.

app.post("/addname", (req, res) => {
 
});
Express Middleware

To fill out the contents of our endpoint, we want to store the firstName and lastName entered by the user into the database. The values for firstName and lastName are in the body of the request that we send to the server. We want to capture that data, convert it to JSON and store it into the database.

Express.js version 4 removed all middleware. To parse the data in the body we will need to add middleware into our application to provide this functionality. We will be using the body-parser module. We need to install it, so in your terminal window enter the following command.

npm install body-parser --save

Once it is installed, we will need to require this module and configure it. The configuration will allow us to pass the data for firstName and lastName in the body to the server. It can also convert that data into JSON format. This will be handy because we can take this formatted data and save it directly into our database.

To add the body-parser middleware to our application and configure it, we can add the following lines directly after the line that sets our port.

var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
Saving data to database

Mongoose provides a save function that will take a JSON object and store it in the database. Our body-parser middleware, will convert the user’s input into the JSON format for us.

To save the data into the database, we need to create a new instance of our model that we created early. We will pass into this instance the user’s input. Once we have it then we just need to enter the command “save”.

Mongoose will return a promise on a save to the database. A promise is what is returned when the save to the database completes. This save will either finish successfully or it will fail. A promise provides two methods that will handle both of these scenarios.

If this save to the database was successful it will return to the .then segment of the promise. In this case we want to send text back the user to let them know the data was saved to the database.

If it fails it will return to the .catch segment of the promise. In this case, we want to send text back to the user telling them the data was not saved to the database. It is best practice to also change the statusCode that is returned from the default 200 to a 400. A 400 statusCode signifies that the operation failed.

Now putting all of this together here is what our final endpoint will look like.

app.post("/addname", (req, res) => {
  var myData = new User(req.body);
  myData.save()
    .then(item => {
      res.send("item saved to database");
    })
    .catch(err => {
      res.status(400).send("unable to save to database");
    });
});
Testing our code

Save your code. Go to your terminal and enter the command node app.js to start our server. Open up your browser and navigate to the URL “http://localhost:3000”. You will see our index.html file displayed to you.

Make sure you have mongo running.

Enter your first name and last name in the input fields and then click the “Add Name” button. You should get back text that says the name has been saved to the database like below.

Access to Code

The final version of the code is available in my Github repo. To access the code click here. Thank you for reading !