fastify

Build A REST Service With Fastify


Fastify is a high-performance HTTP framework for Node.js. Fastify focuses on speed, and it’s inspired by ExpressJS and HapiJS.

In this article, we will learn how to build a RESTFUL service using Fastify by Creating a CRUD API with Fastify.

Learning prerequisites

  • Basic familiarity with Javascript.
  • Nodejs installed on the development machine 
  • MongoDB installed on the development machine
  • Basic Understanding of REST APIs.

Before we start writing code, we need to set up the file structure for our application. We need to initialize a new project by opening our terminal and executing the following commands:

cd desktop
mkdir fastify-service && cd fastify-service
touch index.js
npm init

In the above code, we created a new directory in our desktop, navigated into it, created an index.js file and initialized a node project using npm.

When running npm init  you will be prompted to enter several values. You can leave this blank and update it at a later stage.

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

Now that we have initialized our node project, we need to install all the dependencies that we will need. To do that open up the terminal and type the following:

npm i nodemon mongoose fastify boom

Let me describe the following dependencies:

Nodemon: This is a watcher that restarts our server automatically when we make changes in our application.
Mongoose: It’s an object modeling tool used to asynchronous query MongoDB. It provides a straight-forward, schema-based solution to model your application data.
Fastify: Fastify is a web framework highly focused on providing the best developer experience with the least overhead and a robust plugin architecture. 
Boom: Boom provides a set of utilities for returning HTTP errors for proper error handling.

Setting Up a Fastify Server

To create a simple Fastify server add the following code in the index.js file:

const fastify = require('fastify'); //Bring in Fastify
const PORT = process.env.PORT || 3000;
const app = fastify({
  logger: true
})
// Declare a route
app.get("/", async () => {
  return {
    Message: "Fastify is On Fire"
  }
})
//Funtion To run the server
const start = async () => {
  try {
    await app.listen(PORT)
    app.log.info(`server listening on ${app.server.address().port}`)
  } catch (err) {
    app.log.error(err)
    process.exit(1)
  }
}
start();

We start by requiring the Fastify framework, declare an instance of Fastify, declare our first route, and initialize the server on port 3000, which we stored in the PORT variable.

Fastify comes with a built-in logger which is disabled by default. We enable adding it the Fastify instance:

const app = fastify({
  logger: true
})

To run our application we can now run this on our terminal:

nodemon index.js

After doing this, navigate to http://localhost:3000/ you should see {“Message”: “Fastify is On Fire”} returned in the browser. 

 Now that we have that, we need to set up MongoDB.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.

 Lets create a config directory in our project directory.This is where we will configure mongoose.

mkdir config && cd config
touch db.js

This commands will create a config directory, we navigate into the directory and then create a new file db.js.Now add the following codes in db.js file:

const fastifyPlugin = require('fastify-plugin')
const mongoose = require('mongoose')
// Connect to DB
async function dbConnector(fastify, options) {
    try {
        const url = "mongodb://localhost:27017/fastify-blog"
        const db = await mongoose
            .connect(url, {
                useNewUrlParser: true
            })
        console.log("Database is connected")
        fastify.decorate('mongo', db)
    } catch (err) {
        console.log(err)
    }
}
module.exports = fastifyPlugin(dbConnector)

After doing this, We need to bring this file as a middleware in our application. Middleware is a subset of chained functions called by the Fastify routing layer before the user-defined handler is invoked.


const db = require("./config/db")
app.use(db())

After doing this you should see Database is connected logged on the console. This means that our application is connected to the database.

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


const mongoose = require('mongoose')
const postSchema = new mongoose.Schema({
    title: {
        type: String,
        required: true
    },
    content: {
        type: String,
        required: true
    },
    category: {
        type: String,
        required: true
    },
    author: {
        type: String,
        required: true
    }
}, {
    timestamps: true
})
module.exports = mongoose.model('POST', postSchema)

We start by creating our mongoose schema which takes in an object defining the property of the blog schema. Mongoose converts the schema into a document in the database and those properties will be converted into fields in our document.

Now let’s create our routes. Below is the list of endpoints we will be creating:

  • HTTP POST /blog  —— Create a new blog post.
  • HTTP GET /blog  ——- Get all blog post.
  • HTTP DELETE /blog/:blogId  —— Delete a  blog post.
  • HTTP PUT /blog/:blogId  ——- Update a blog post.

Create a new folder within the root directory called routes, and within it create a new file called postRoutes.js and add the following code: 


const blogController = require('../controller/blogController');
const routes = [{
        method: 'GET',
        url: '/api/posts',
        handler: blogController.getAllPost
    },
    {
        method: 'GET',
        url: '/api/post/:id',
        handler: blogController.getSinglePost
    },
    {
        method: 'POST',
        url: '/api/post',
        handler: blogController.addNewPost,
    },
    {
        method: 'PUT',
        url: '/api/post/:id',
        handler: blogController.updatePost
    },
    {
        method: 'DELETE',
        url: '/api/post/:id',
        handler: blogController.deletePost
    }
]
module.exports = routes

Here we require a blogController file which is yet to created. Inside the file, we will create some methods that will handle our routes. It’s a an excellent concept to separate our business logic from our routes.

Now we need to create this controller file that will handle our routes. Create a new folder within the root directory called controller, and within it create a new file called blogController.js and add the following code:


const boom = require('boom')
const Blog = require("../model/Post")
// get all post 
exports.getAllPost = async (req, reply) => {
    try {
        let posts = await Blog.find();
        return posts;
    } catch (err) {
        throw boom.boomify(err)
    }
}
// get single post by id 
exports.getSinglePost = async (req, reply) => {
    try {
        const id = req.params.id
        let post = await Blog.findById(id);
        return post
    } catch (err) {
        throw boom.boomify(err)
    }
}
exports.addNewPost = async (req, reply) => {
    try {
        let post = new Blog(req.body);
        let newpost = await post.save();
        return newpost
    } catch (err) {
        throw boom.boomify(err)
    }
}
exports.updatePost = async (req, reply) => {
    try {
        const id = req.params.id
        let result = await Blog.findByIdAndUpdate(id, req.body, {
            new: true
        });
        return result
    } catch (err) {
        throw boom.boomify(err)
    }
}
exports.deletePost = async (req, reply) => {
    try {
        const id = req.params.id
        let result = await Blog.findByIdAndDelete(
            id
        );
        return {Message:"Post Deleted"}
    } catch (err) {
        throw boom.boomify(err)
    }
}

 

Here we start by requiring boom to handle our errors. We export each of our functions so that it is accessible by our route file. Each function is wrapped in a try and catch block. The catch block uses the boom package to throw the errors.

Now that we have our routes and controller file, we need to bring it into the index.js file by requiring it.

const routes = require("./routes/postRoutes");

After doing this we then need to loop over the routes array to initialize them with Fastify. After you have required the route file, add the following code to loop over the route array:

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

Now that we have initialised the routes we need to start testing the endpoints.let’s test them using POSTMAN.

Create A New Blog Post

REST Service With Fastify

Always remember to set the request type to JSON

Get All Posts

REST Service With Fastify

Get Blog Post by ID

REST Service With Fastify

From the list of all posts,get an Id from one of the documents in the collection and pass it as a params in the route.

Updating A Blog Post

REST Service With Fastify

Remember to set the request type to a PUT request

Deleting A Post

REST Service With Fastify

Remember to set the request type to a DELETE request

Conclusion

Building a REST service using Fastify is quite easy. We could use it to develop larger applications like an E-commerce platform. It could be integrated with any frontend framework like Angular, Vue, or React. Understanding the basics is all that matters.

For source code click here


Share on social media

//