Now we’re moving from Express basics to REST API design, which is how most Node.js backend apps structure their endpoints. Let’s go step by step.
🌐 1. What is a REST API?
REST (Representational State Transfer) is an architectural style for web services.
Key principles:
-
Stateless: Each request contains all info to process it.
-
Resource-based: Endpoints represent resources (e.g., users, posts).
-
HTTP methods: Use standard verbs to act on resources:
-
GET
→ retrieve data -
POST
→ create a resource -
PUT
/PATCH
→ update a resource -
DELETE
→ remove a resource
-
-
JSON: Responses are usually in JSON format.
🛠️ 2. REST API Folder Structure
Common structure with Express:
src/
├── routes/
│ └── userRoutes.js
├── controllers/
│ └── userController.js
├── models/
│ └── User.js
├── middlewares/
│ └── authMiddleware.js
├── app.js
└── server.js
-
routes/
→ define endpoints -
controllers/
→ business logic -
models/
→ database schema -
middlewares/
→ auth, validation, error handling
📄 3. CRUD Routes Example
Model Example (User.js
)
const mongoose = require("mongoose");
const userSchema = new mongoose.Schema({
name: String,
email: String
});
module.exports = mongoose.model("User", userSchema);
Controller Example (userController.js
)
const User = require("../models/User");
exports.getUsers = async (req, res) => {
const users = await User.find();
res.json(users);
};
exports.createUser = async (req, res) => {
const user = new User(req.body);
await user.save();
res.status(201).json(user);
};
exports.updateUser = async (req, res) => {
const { id } = req.params;
const user = await User.findByIdAndUpdate(id, req.body, { new: true });
res.json(user);
};
exports.deleteUser = async (req, res) => {
const { id } = req.params;
await User.findByIdAndDelete(id);
res.status(204).send();
};
Routes Example (userRoutes.js
)
const express = require("express");
const router = express.Router();
const userController = require("../controllers/userController");
router.get("/", userController.getUsers);
router.post("/", userController.createUser);
router.put("/:id", userController.updateUser);
router.delete("/:id", userController.deleteUser);
module.exports = router;
App Setup (app.js
)
const express = require("express");
const userRoutes = require("./routes/userRoutes");
const app = express();
app.use(express.json());
app.use("/users", userRoutes);
module.exports = app;
⚡ 4. Query Parameters & Filtering
REST APIs often support filtering, sorting, pagination via query params:
// GET /users?limit=10&sort=name
exports.getUsers = async (req, res) => {
const { limit = 10, sort = "name" } = req.query;
const users = await User.find().limit(Number(limit)).sort(sort);
res.json(users);
};
🔐 5. Authentication & Authorization
-
JWT tokens are commonly used:
-
Middleware checks
Authorization
header -
Verifies token
-
Adds user info to
req.user
-
Example middleware:
const jwt = require("jsonwebtoken");
module.exports = (req, res, next) => {
const token = req.headers["authorization"];
if (!token) return res.status(401).json({ error: "Unauthorized" });
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (err) {
res.status(401).json({ error: "Invalid token" });
}
};
✅ 6. REST API Best Practices
-
Use plural resource names (
/users
,/posts
). -
Use HTTP status codes correctly (200, 201, 204, 400, 404, 500).
-
Keep consistent JSON response format:
{
"success": true,
"data": {...},
"error": null
}
-
Validate request body using libraries like
Joi
orexpress-validator
. -
Version your API:
/api/v1/users
.