How I built my blog API

Introduction

In this article, we will be discussing the blog backend API that I built using Node.js, Express, and MongoDB. This project's requirements include

  • A user should be able to sign up and sign in to the blog app

  • Use JWT as an authentication strategy and expire the token after 1 hour

  • Logged in and not logged in users should be able to get a list of published blogs created

  • Signed in users should be able to create, update, read and delete their posts

  • Blogs should be paginated, searchable by author, title and tags

Technologies Used

Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine that allows developers to execute JavaScript code on the server side. It is fast, scalable, and widely used for building APIs and other server-side applications.

Express is a fast, minimalist web framework for Node.js that provides a robust set of features for building web applications. It simplifies the process of routing, parsing requests, and handling responses, and is a popular choice for building APIs.

MongoDB is a NoSQL database that stores data in flexible, JSON-like documents. It is well-suited for working with Node.js and is widely used for building modern web applications.

Code Structure

The code for the blog backend API is structured using the Model-View-Controller (MVC) pattern, which separates the application into three distinct layers: the model, the view, and the controller. The model layer represents the data and business logic of the application, the view layer represents the user interface, and the controller layer acts as a mediator between the two.

The API code is organized into a set of files that correspond to the different layers of the MVC pattern. For example, the model layer consists of files that define the data models for blog posts and user accounts, and the controller layer consists of files that define the endpoints and logic for handling API requests.

Middleware

Express middleware is a function that executes before the main route handler and can modify the request and response objects or terminate the request-response cycle. The blog backend API uses several pieces of middleware to perform tasks such as parsing the request body, validating JWTs, and handling errors.

Routes and Controllers

The API is built using a RESTful architecture, which means that it follows a set of conventions for naming and organizing endpoints, and uses HTTP verbs (e.g. GET, POST, PUT, DELETE) to indicate the type of operation being performed. These endpoints are defined in the controller layer using Express routes.

For example, the API has a route for creating a new blog post that looks like this:

router.post('/', authController.authorize, blogController.createBlog);

This route maps the POST request to the authorize function in the authController module and createBlog function in the postController module, which handles the request and sends a response back to the client.

Technical Deep Dive

The blog backend API is organized into a set of endpoints that enables a user to perform CRUD (create, read, update, delete) operations on blog posts and user accounts. The API is built using a RESTful architecture, which means that it follows a set of conventions for naming and organizing endpoints, and uses HTTP verbs (e.g. GET, POST, PUT, DELETE) to indicate the type of operation being performed.

The API's data model consists of two main types of resources: blog posts and user accounts.

Here's the data model for the blog

title: {
        type: String,
        required: [true, 'Your blog needs a title'],
        unique: true
    },
    description: {
        type: String,
        required: [true, 'Your blog needs a description'],
    },
    body: {
        type: String,
        required: [true, 'Your blog needs a body'],
    },
    tags: {
        type: Array
    },
    author: {
        type: objectId,
        ref: 'User'
    },
    state: {
        type: String,
        enum: ['draft', 'published'],
        default: 'draft'
    },
    read_count: {
        type: Number,
        default: 0
    },
    reading_time: {
        type: String
    }
}

Here's the data model for the user accounts

email: {
        type: String,
        required: true,
        unique: [true, 'Please input your email']
    },
    first_name: {
        type: String,
        required: [true, 'Please input your first name']
    },
    last_name: {
        type: String,
        required: [true, 'Please input your last name']
    },
    password: {
        type: String,
        required: [true, 'Please set a password'],
        minlength: 8,    },
    passwordConfirm: {
        type: String,
        required: [true, 'Please confirm password'],
        minlength: 8,
    },
}

The API uses MongoDB to store and retrieve these resources and uses JSON Web Tokens (JWTs) to authenticate and authorize user requests.

My process

  1. After setting up the project, install the necessary dependencies

     "dependencies": {
         "bcrypt": "^5.1.0",
         "cookie-parser": "^1.4.6",
         "cross-env": "^7.0.3",
         "dotenv": "^16.0.3",
         "express": "^4.18.2",
         "jsonwebtoken": "^8.5.1",
         "mongoose": "^6.7.0"
       },
    
  2. Connect the application to the mongo atlas database and export

     const mongoose = require('mongoose');
     require('dotenv').config();
    
     const MONGODB_ATLAS_URI=process.env.MONGODB_ATLAS_URI
     const TEST_MONGODB_URI = process.env.TEST_MONGODB_URI
     // connect to mongodb
     function connectToMongoDB() {
         mongoose.connect(MONGODB_ATLAS_URI);
    
         mongoose.connection.on('connected', () => {
             console.log('Connected to MongoDB successfully');
         });
    
         mongoose.connection.on('error', (err) => {
             console.log('Error connecting to MongoDB', err);
         })
     }
    
     module.exports = { connectToMongoDB };
    
    1. Create the server and import the necessary modules

    2. Create the controllers and routes(endpoints) and middleware to handle user sign up, sign in, authentication. For sign up the user details is created and stored in th database with user password hashed. For sign in, the user input is compared against what's in the database. When they match, a token is generated for the user and user is successfully signed in.

    3. Next, was create the controllers and routes and middleware to handle the CRUD operations of the blog. Here's the snippet of the routes used for performing CRUD operations

       const router = require('express').Router()
       const blogController = require('../controllers/blog.controller')
       const authController = require('../controllers/auth.controller')
      
       router.post('/', authController.authorize,  blogController.createBlog)
       router.get('/', blogController.getBlogs)
       router.get('/:blogId', blogController.getABlog)
       router.patch('/update/:blogId', authController.authorize, blogController.updateBlog)
       router.get('/:id', authController.authorize, blogController.getOwnerBlogs)
       router.delete('/delete/:blogId', authController.authorize, blogController.deleteBlog)
      
       module.exports = router
      

      authController.authorize is the middleware used to check is a user is authorized to perform certain actions. It checks and verifies the token passed in the request. If user is authorized, then next action is performed.

       exports.createBlog = async (req, res, next) => {
         try {
               req.body.author = req.user
               const blog = await Blog.create(req.body)
      
               blog.reading_time = readingTime(blog.body)
               blog.save()
               // Response
               return res.status(201).json({
               status: "success",
               data: {
                       blog,
                     },
               });
           } catch (err) {
               return next(new appError(err.statusCode, err))
         }
       }
      

      This is the controller that handles creating a blog post.

Conclusion

In this article, I have given an overview of a blog backend API I built using Node.js, Express, and MongoDB. I discussed the technologies used, the code structure, and the technical details of how the API works.

Here's the github link to the project. Do check it out