Skip to content

Building a REST API with Node.js and MongoDB: A Step-by-Step Guide

Building a REST API with Node.js and MongoDB: A Step-by-Step Guide

Building a REST API is essential for modern web applications, enabling you to interact with your backend using standard HTTP methods. In this guide, we’ll build a REST API with Node.js, Express, and MongoDB, covering everything from setting up the project to implementing CRUD operations. By the end, you’ll have a fully functional API that you can use as a backend for web or mobile applications.

REST API Architecture Overview

graph TB
    subgraph "Client Layer"
        WEB[Web Application]
        MOBILE[Mobile App]
        API_CLIENT[API Client]
    end
    
    subgraph "HTTP Methods"
        GET[GET /users<br/>Read Operations]
        POST[POST /users<br/>Create Operations]
        PUT[PUT /users/:id<br/>Update Operations]
        DELETE[DELETE /users/:id<br/>Delete Operations]
    end
    
    subgraph "Express.js Server"
        ROUTER[Express Router<br/>Route Handling]
        MIDDLEWARE[Middleware<br/>JSON Parser, Auth]
        CONTROLLER[Controllers<br/>Business Logic]
    end
    
    subgraph "Database Layer"
        MONGOOSE[Mongoose ODM<br/>Object Modeling]
        MONGODB[(MongoDB Database<br/>Document Storage)]
    end
    
    subgraph "Data Flow"
        REQUEST[HTTP Request]
        RESPONSE[HTTP Response]
        VALIDATION[Data Validation]
        PERSISTENCE[Data Persistence]
    end
    
    WEB --> GET
    MOBILE --> POST
    API_CLIENT --> PUT
    API_CLIENT --> DELETE
    
    GET --> ROUTER
    POST --> ROUTER
    PUT --> ROUTER
    DELETE --> ROUTER
    
    ROUTER --> MIDDLEWARE
    MIDDLEWARE --> CONTROLLER
    CONTROLLER --> MONGOOSE
    MONGOOSE --> MONGODB
    
    MONGODB --> PERSISTENCE
    PERSISTENCE --> VALIDATION
    VALIDATION --> RESPONSE
    
    style GET fill:#e8f5e8
    style POST fill:#e1f5fe
    style PUT fill:#fff3e0
    style DELETE fill:#ffebee
    style MONGODB fill:#f3e5f5

Prerequisites

To follow along with this tutorial, you’ll need:

  1. Node.js and npm installed on your system.
  2. MongoDB installed locally or access to a MongoDB cloud instance (e.g., MongoDB Atlas).
  3. Basic understanding of JavaScript, Node.js, and REST APIs.

Project Setup

First, let’s set up a new Node.js project and install the necessary dependencies.

Step 1: Create a New Project

Open a terminal, create a new directory, and initialize a Node.js project:

# @filename: script.sh
mkdir rest-api
cd rest-api
npm init -y

Step 2: Install Dependencies

We’ll use Express for the web server and Mongoose for connecting to MongoDB.

npm install express mongoose dotenv
  • express: A minimalist web framework for building REST APIs.
  • mongoose: An ODM (Object Data Modeling) library for MongoDB, which simplifies database interactions.
  • dotenv: Loads environment variables from a .env file.

Configuring MongoDB Connection

We’ll store our MongoDB connection string in an .env file to keep it secure.

Step 1: Create a .env File

In the project root, create a .env file and add your MongoDB URI:

MONGODB_URI=mongodb://localhost:27017/rest_api
PORT=5000

Replace the MONGODB_URI value with your actual MongoDB connection string.

Step 2: Set Up the Database Connection

In the root directory, create a new file named server.js. This file will be the entry point for our application.

server.js

// @filename: server.js
require('dotenv').config()
const express = require('express')
const mongoose = require('mongoose')

const app = express()

// Middleware
app.use(express.json())

// Connect to MongoDB
mongoose
  .connect(process.env.MONGODB_URI, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  })
  .then(() => console.log('Connected to MongoDB'))
  .catch((error) => console.error('MongoDB connection error:', error))

// Start the server
const port = process.env.PORT || 3000
app.listen(port, () => {
  console.log(`Server running on port ${port}`)
})

In this setup:

  • dotenv loads the .env variables.
  • mongoose.connect connects to the MongoDB database.
  • The Express server listens on the port specified in .env or defaults to 3000.

Run the server to test the connection:

node server.js

If the connection is successful, you’ll see the message “Connected to MongoDB” in the terminal.


Defining the Data Model with Mongoose

Let’s create a simple data model for a User with fields for name, email, and age.

Step 1: Create a models Directory

Inside the project directory, create a models folder and a file named User.js.

Step 2: Define the User Model

In models/User.js, define the User schema:

// @filename: config.js
const mongoose = require('mongoose')

const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
  },
  email: {
    type: String,
    required: true,
    unique: true,
  },
  age: {
    type: Number,
    required: true,
  },
})

module.exports = mongoose.model('User', userSchema)

This schema defines the structure of a user document with three fields: name, email, and age. Each field has a type and a validation rule.

User Schema Structure

erDiagram
    USER {
        ObjectId _id PK "MongoDB Generated"
        String name "Required, Non-empty"
        String email UK "Required, Unique"
        Number age "Required, Positive Integer"
        Date createdAt "Auto-generated"
        Date updatedAt "Auto-updated"
    }
    
    USER ||--o{ USER_SESSION : has
    USER ||--o{ USER_PROFILE : extends
    
    USER_SESSION {
        ObjectId _id PK
        ObjectId userId FK
        String token
        Date expiresAt
    }
    
    USER_PROFILE {
        ObjectId _id PK
        ObjectId userId FK
        String avatar
        String bio
        Object preferences
    }

Creating CRUD Routes for the API

Now, let’s create CRUD routes to manage users. We’ll define routes for creating, reading, updating, and deleting users.

Step 1: Create a routes Directory

Inside the project directory, create a routes folder and a file named users.js.

Step 2: Define User Routes

In routes/users.js, define routes for each CRUD operation:

// @filename: routes.js
const express = require('express')
const router = express.Router()
const User = require('../models/User')

// CREATE a new user
router.post('/', async (req, res) => {
  try {
    const user = new User(req.body)
    await user.save()
    res.status(201).json(user)
  } catch (error) {
    res.status(400).json({ message: error.message })
  }
})

// READ all users
router.get('/', async (req, res) => {
  try {
    const users = await User.find()
    res.json(users)
  } catch (error) {
    res.status(500).json({ message: error.message })
  }
})

// READ a single user by ID
router.get('/:id', async (req, res) => {
  try {
    const user = await User.findById(req.params.id)
    if (!user) return res.status(404).json({ message: 'User not found' })
    res.json(user)
  } catch (error) {
    res.status(500).json({ message: error.message })
  }
})

// UPDATE a user by ID
router.put('/:id', async (req, res) => {
  try {
    const user = await User.findByIdAndUpdate(req.params.id, req.body, {
      new: true,
    })
    if (!user) return res.status(404).json({ message: 'User not found' })
    res.json(user)
  } catch (error) {
    res.status(400).json({ message: error.message })
  }
})

// DELETE a user by ID
router.delete('/:id', async (req, res) => {
  try {
    const user = await User.findByIdAndDelete(req.params.id)
    if (!user) return res.status(404).json({ message: 'User not found' })
    res.json({ message: 'User deleted' })
  } catch (error) {
    res.status(500).json({ message: error.message })
  }
})

module.exports = router

Each route performs a CRUD operation:

  • POST /users: Creates a new user.
  • GET /users: Retrieves all users.
  • GET /users/:id: Retrieves a single user by ID.
  • PUT /users/:id: Updates a user by ID.
  • DELETE /users/:id: Deletes a user by ID.

CRUD Operations Flow

sequenceDiagram
    participant Client
    participant Express as Express Router
    participant Mongoose as Mongoose ODM
    participant MongoDB as MongoDB Database
    
    Note over Client,MongoDB: CREATE Operation (POST /users)
    Client->>Express: POST /users {name, email, age}
    Express->>Express: Validate request body
    Express->>Mongoose: new User(data).save()
    Mongoose->>MongoDB: Insert document
    MongoDB-->>Mongoose: Document created with _id
    Mongoose-->>Express: User object with _id
    Express-->>Client: 201 Created + User data
    
    Note over Client,MongoDB: READ Operation (GET /users)
    Client->>Express: GET /users
    Express->>Mongoose: User.find()
    Mongoose->>MongoDB: Query all documents
    MongoDB-->>Mongoose: Array of user documents
    Mongoose-->>Express: Array of User objects
    Express-->>Client: 200 OK + Users array
    
    Note over Client,MongoDB: UPDATE Operation (PUT /users/:id)
    Client->>Express: PUT /users/123 {name: "New Name"}
    Express->>Mongoose: User.findByIdAndUpdate(id, data)
    Mongoose->>MongoDB: Update document by _id
    MongoDB-->>Mongoose: Updated document or null
    Mongoose-->>Express: Updated User object or null
    Express-->>Client: 200 OK + Updated user OR 404 Not Found
    
    Note over Client,MongoDB: DELETE Operation (DELETE /users/:id)
    Client->>Express: DELETE /users/123
    Express->>Mongoose: User.findByIdAndDelete(id)
    Mongoose->>MongoDB: Delete document by _id
    MongoDB-->>Mongoose: Deleted document or null
    Mongoose-->>Express: Deleted User object or null
    Express-->>Client: 200 OK + Success message OR 404 Not Found
  • GET /users
Node.js MongoDB REST API Express CRUD Backend Development
Share:

Continue Reading

Building a RESTful API with Node.js and Express: A Step-by-Step Guide

Creating a RESTful API in Node.js with Express is ideal for building scalable and efficient backends. This guide walks you through setting up a RESTful API with Express, handling CRUD operations, connecting to MongoDB, and structuring the project for scalability.

Read article
Node.jsJavaScriptBackend

Implementing File Uploads in Node.js with Multer and Express

Handling file uploads in a Node.js application allows users to share images, documents, and other media files directly with your server. Using Multer with Express, you can configure a robust file upload system that securely manages files, validates their types, and stores them effectively. This guide will walk you through setting up file uploads, covering everything from configuring storage to securing and validating uploaded files.

Read article
Node.jsJavaScriptBackend

Understanding and Implementing CORS in Node.js and Express

CORS (Cross-Origin Resource Sharing) is a security feature in web browsers that restricts web pages from making requests to a different domain than the one that served the original page. By configuring CORS in a Node.js and Express application, you can control which origins are allowed to interact with your server. This guide explains the concept of CORS, why it’s essential, and how to configure it in Express.

Read article
Node.jsJavaScriptBackend