Create REST API Using NodeJS and MongoDB

Create REST API Using NodeJS and MongoDB

ยท

9 min read

Ok, welcome to this article I just want to share how I make the REST API using NodeJS, MongoDB, and Express. In this article, you will learn how to create a basic CRUD API and then test the API using Hoopscotch.io. This content is just basically the next day I will create more content about making API and securing node js applications.

So with that said, let's get started


Prerequisites

Before building this API, we need to ensure some dependencies already run on your computer including:

  1. MongoDB

  2. NodeJS

If you're not already installed the stack above, please follow this step and instructions. Skip this section if you're already installed


Create a Project folder and repository

Ok, before we jump in, first we need to create the application folder for our application. Create a new folder called node-crud-rest-api. Open the folder using your code editor, in my case, I will use VSCode. Your project will be empty like below.

Connect with Repository

this step is optional if you want to upload your code into the repository. Create a new project in GitHub then copy the git URL.

Create a new file called '.gitignore', this file is used to handle and manage the files which one should include and exclude in git. This is useful when you're not want to expose your file to the public repository.

Add this content to your .gitignore file

# Ignore som fike for your repository
/node_modules
*.env
.env

Now with this code when you add the file using git the node_module folder, and the env file will not be included.

Now open the terminal and connect your local to the remote repo

# Create git project
git init

# Connect your local repo and remoteg
git remote add origin [YOUR REMOTE REPO URl]

Clean Code (Optional)

If you need to clean your code use the prettier. Install the prettier extension, then create a .prettierrc file. Place this code inside

{
  "semi": false,
  "singleQuote": true
}


Initialize Node Project

Initialize the node project by running this command in your terminal. This will create a project initialization and generate a new file called package.json

# Create node project by running this command in terminal
npm init -y

Now let's update the script of your package.

{
  "name": "crud-node-rest-api",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.js",
  "scripts": {
    "dev": "nodemon src/index.js",
    "start": "node src/index.js"
  },
  "keywords": [],
  "author": "nyomansunima",
  "license": "ISC"
}


Install Dependencies

Install some dependencies to run the application including:

  • express (A small Framework that allows creating REST API)

  • mongoose (Library to connect MongoDB and create object mapping)

  • morgan (A middleware to create HTTP Log when your API is accessed)

  • helmet (Secure your API from Script attack in the header)

  • nodemon (Allow to restart your server when the code is changed)

  • express-brute (Limiting your API access from the same API to avoid brute force)

  • dotenv (Allow to access the variable from .env file)

  • body-parser (Parse the response body using json)

  • cors (Allow to sharing the resource from different origin in browser)

Now open your terminal and run this command to install dependencies.

# Install deps
npm i -S express mongoose morgan helmet express-brute dotenv cors body-parser

# Install deps in development
npm i -D nodemon


Create folder workspace

Now to manage and separate our code is to create a separate folder for a different purpose, you can follow some architecture. but in this case, I just use the simple one.

Create the folder using this pattern

  • src (all of your code is placed here)

    • controllers (manage the app routes)

    • services (separate the business logic and function here)

    • models (payload, database model, and other classes)

    • utils (place all your utils code here)


Add Environment variable

Create a new file in the root folder called .env. Inside this file will store some data and keys for the application including the database, port, and others.

# APPLICATION SETTINGS
PORT = [YOUR_APP_PORT]

# DATABASE CONNECTION
DATABASE_PORT = [YOUR_DATABASE_PORT]
DATABASE_NAME = [YOUR_DATABASE_NAME]
DATABASE_URL = [YOUR_DATABASE_URL]
DATABASE_USER = [YOUR_DATABASE_USER]
DATABASE_PASS = [YOUR_DATABASE_PASS]

Now, let's change some variables using your own.


Add the Database Model & Connection

  • Create a new file inside the utils/ folder and named it as database.js, then add this code inside.

      const mongoose = require('mongoose')
    
      async function connectDatabase() {
        try {
          await mongoose.connect(
            `mongodb://${process.env.DATABASE_URL}:${process.env.DATABASE_PORT}`,
            {
              dbName: process.env.DATABASE_NAME,
              auth: {
                username: process.env.DATABASE_USER,
                password: process.env.DATABASE_PASS,
              },
            }
          )
          console.log('๐Ÿ” Database Connected')
        } catch (error) {
          console.log('Opps, failed to connect database')
        }
      }
    
      module.exports = {
        connectDatabase,
      }
    

    Connect the database, variable that we created before in .env file. This code will be used in the index.js file later. But for now we focus on database first.

  • Create a new file called user.js inside the models folder, this will be the user schema and all of the user information

      const { Schema, model } = require('mongoose')
    
      const UserSchema = new Schema(
        {
          name: String,
          email: String,
          username: String,
          bio: String,
        },
        { timestamps: true }
      )
    
      const UserModel = model('User', UserSchema, 'users')
    
      module.exports = {
        UserSchema,
        UserModel,
      }
    

    You can also create another model and schema using another file. This will help you to create a clear code splitting. In this example I just add simple user information, you can add what you want.


Create Service

Service is used to handle all of the logic for the user, including manipulating, generating, and so on.

Create a file called user.js then paste this code inside

const { UserModel } = require('../models/user')

class UserService {
  async createUser(body) {
    const newUser = new UserModel(body)
    const res = await newUser.save()
    return res
  }

  async updateUser(id, body) {
    await UserModel.updateOne({ _id: id }, { ...body })
    const res = UserModel.findById(id)
    return res
  }

  async deleteUser(id) {
    await UserModel.deleteOne({ _id: id })
  }

  async listUser() {
    const res = await UserModel.find()
    return res
  }

  async findUser(id) {
    const res = await UserModel.findById(id)
    return res
  }
}
const userService = new UserService()
module.exports = userService

You can see some function is all about the user with simple operation to create, update, delete, and list the user. We just need to call the `UserModel` and then use the predefined function from the mongoose object. You also can create a custom one like adding authentication and so on.


Create Controllers

Create a new file called user.js inside the controllers folder then put this code inside

const userService = require('../services/user')

class UserController {
  async createUser(req, res) {
    const body = req.body
    res.json(await userService.createUser(body))
  }

  async updateUser(req, res) {
    const body = req.body
    const id = req.params.id
    res.json(await userService.updateUser(id, body))
  }

  async deleteUser(req, res) {
    const id = req.params.id
    res.json(await userService.deleteUser(id))
  }

  async findUser(req, res) {
    const id = req.params.id
    res.json(await userService.findUser(id))
  }

  async listUser(req, res) {
    res.json(await userService.listUser())
  }
}

const userController = new UserController()
module.exports = userController

The controller is a mapping from the route and the service. We also can handle some exception manuals or use third-party middleware. Send the result using the `res.json` function.


Handle the API Routes

Create a new file called `routes.js` inside the src folder. Then put this code inside.

const express = require('express')
const userController = require('./controllers/user')

// define the application router
const router = express.Router()

// add the user routes
router.get('/user/list', userController.listUser)
router.get('/user/:id', userController.findUser)
router.post('/user', userController.createUser)
router.put('/user/:id', userController.updateUser)
router.delete('/user/:id', userController.deleteUser)

module.exports = router

Now mapping the route with the controller. By using this way your code will look cleaner.


Bootstrap the app

  • Now after all we need is created, we can combine it all for our application. So let's create a new file called `index.js` inside the src folder. This file becomes the main file to run using nodejs.

  • Import for all dependencies, router, and database connections.

      const express = require('express')
      const morgan = require('morgan')
      const helmet = require('helmet')
      const { config } = require('dotenv')
      const bodyParser = require('body-parser')
      const cors = require('cors')
      const router = require('./routes')
      const { connectDatabase } = require('./utils/database')
    
  • Now create a function to bootstrap the application.

    
      /**
       * bootstrap all deps
       * and your app here
       */
      async function bootstrap() {
        config()
        await connectDatabase()
        const app = express()
    
        // add the middleware and
        // plugins
        app.use(helmet())
        app.use(morgan('combined'))
        app.use(cors({ origin: '*' }))
        app.use(bodyParser.json())
        app.use(bodyParser.urlencoded({ extended: true }))
    
        // all you route in one place
        app.use('/api/', router)
    
        // add the base response
        app.use('/', (req, res) => {
          res.send('Welcome in CRUD API')
        })
    
        // running the application
        // on specify port
        const PORT = process.env.PORT || 4000
        app.listen(PORT, () => {
          console.log(`Application running on http://localhost:${PORT}`)
        })
      }
    

    In this function you first need to call the config, this will load all the environment variables from `.env` file. Don't forget to use the helmet, cors, morgan, and body parser. In last you can listen to the application.

  • Run the application by calling `bootstrap()`. if we combine all inside the index.js file the code will look like this

      const express = require('express')
      const morgan = require('morgan')
      const helmet = require('helmet')
      const { config } = require('dotenv')
      const bodyParser = require('body-parser')
      const cors = require('cors')
      const router = require('./routes')
      const { connectDatabase } = require('./utils/database')
    
      /**
       * bootstrap all deps
       * and your app here
       */
      async function bootstrap() {
        config()
        await connectDatabase()
        const app = express()
    
        // add the middleware and
        // plugins
        app.use(helmet())
        app.use(morgan('combined'))
        app.use(cors({ origin: '*' }))
        app.use(bodyParser.json())
        app.use(bodyParser.urlencoded({ extended: true }))
    
        // all you route in one place
        app.use('/api/', router)
    
        // add the base response
        app.use('/', (req, res) => {
          res.send('Welcome in CRUD API')
        })
    
        // running the application
        // on specify port
        const PORT = process.env.PORT || 4000
        app.listen(PORT, () => {
          console.log(`Application running on http://localhost:${PORT}`)
        })
      }
    
      // run the application
      bootstrap()
    


Run Application

  • Let's go to the terminal, then type `npm run dev`. This will trigger the nodemon to watch every change in index.js file so that you can update the application automatically.

  • If you want to go into production when the application is complete. You can run by using `npm run start`. This will tell the node js to run the file index.js


Test the REST API

  • Open https://hoppscotch.io/ in your browser. You can change the URL and the method to test the API. You can see the test below


Suggestion

You can clone this CRUD NODE REST API and start to run the application if MongoDB and NodeJS are installed.

This article is just a basic one. There is a lot of upgrades you can add like securing the app, Optimizing the production, and advanced combination like adding devops, and docker. So keep going, I will create another article later to cover it all until complete.

ย