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.
Prerequisites
To follow along with this tutorial, you’ll need:
- Node.js and npm installed on your system.
- MongoDB installed locally or access to a MongoDB cloud instance (e.g., MongoDB Atlas).
- 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:
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
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 to3000
.
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:
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.
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:
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