2026 Guide: Building a REST API with Node.js and Express
Let’s be honest: REST APIs aren’t going anywhere. Even in 2026, they’re still the backbone of most web services — simple, predictable, and battle-tested. Node.js and Express remain a go-to combo for building them fast, especially when you need something lightweight and scalable. This guide cuts through the noise and shows you how to build a clean, production-ready REST API in 2026 — no hype, just working code.
1. Start with the Right Setup
Don’t just npm init -y && npm install express. That’s how you end up with a mess. Use a modern setup from day one.
npm init -y
npm install express dotenv cors helmet morgan
npm install --save-dev nodemon eslint prettier
-
helmet: Security headers, non-negotiable. -
cors: Unless you loveCORS errorin the console. -
morgan: Logging HTTP requests — essential for debugging. -
dotenv: Environment variables. Keep secrets out of code.
Set up your package.json scripts:
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"lint": "eslint .",
"format": "prettier --write ."
}
And your basic server.js:
import express from "express";
import cors from "cors";
import helmet from "helmet";
import morgan from "morgan";
import dotenv from "dotenv";
dotenv.config();
const app = express();
app.use(helmet());
app.use(cors());
app.use(morgan("dev"));
app.use(express.json());
app.get("/", (req, res) => {
res.json({ message: "REST API alive in 2026" });
});
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Run npm run dev and you’re live.
2. Structure Your Code (Don’t Dump Everything in server.js)
You’re not writing a tutorial — you’re building something maintainable. Use a basic structure:
/src
/routes
/controllers
/middleware
/utils
server.js
Example: /src/routes/todos.js
import { Router } from "express";
import { getTodos, createTodo } from "../controllers/todoController.js";
const router = Router();
router.route("/").get(getTodos).post(createTodo);
export default router;
Controller: /src/controllers/todoController.js
let todos = []; // Pretend this is a DB
export const getTodos = (req, res) => {
res.json(todos);
};
export const createTodo = (req, res) => {
const { title } = req.body;
if (!title) return res.status(400).json({ error: "Title required" });
const todo = { id: todos.length + 1, title, done: false };
todos.push(todo);
res.status(201).json(todo);
};
Then in server.js:
import todoRoutes from "./routes/todos.js";
app.use("/api/todos", todoRoutes);
Clean. Scalable. No 500-line server.js.
3. Add Middleware for Validation and Errors
Don’t trust client input. Validate early.
Create /src/middleware/validateTodo.js:
export const validateTodo = (req, res, next) => {
const { title } = req.body;
if (!title || typeof title !== "string" || title.trim().length === 0) {
return res.status(400).json({ error: "Valid title is required" });
}
next();
};
Use it in your route:
router.route("/").get(getTodos).post(validateTodo, createTodo);
Also, handle errors globally. Create /src/middleware/errorHandler.js:
export const errorHandler = (err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: "Something went wrong!" });
};
And in server.js:
app.use(errorHandler);
Now unhandled errors won’t crash your server or return HTML.
4. Use Environment Variables and Config
No hardcoded ports, URLs, or secrets.
.env:
PORT=5000
NODE_ENV=development
API_BASE=/api
Create /src/config.js:
export default {
port: process.env.PORT || 5000,
apiBase: process.env.API_BASE || "/api",
env: process.env.NODE_ENV || "development",
};
Use it in server.js:
import config from "./config.js";
app.listen(config.port, () => {
console.log(`Server running on port ${config.port}`);
});
Now you can deploy to different environments without touching code.
5. Add Basic Testing (Yes, Really)
You don’t need Jest + 10 libraries. Use supertest and node:test.
Install:
npm install --save-dev supertest
Create /tests/todo.test.js:
js
import { describe, it } from "node:test";
import assert from "node:assert";
import request from "supertest";
import app from "../src/server.js";
---
☕ **Playful**
Top comments (0)