
Why Express for REST APIs?
Express is the most popular web framework for Node.js, and for good reason. It’s minimal, flexible, and makes building REST APIs straightforward. You don't need heavy configuration or a complex folder structure—just a few lines of code and you're handling HTTP requests.
If you know a bit of JavaScript and have Node.js installed, you're ready to go. Let’s build a tiny API that manages a list of tasks. It won't be production-ready, but it will show you the core concepts you'll use every day.
Setting Up Your Project
First, create a new folder and initialize it.
mkdir my-api && cd my-api
npm init -y
npm install express
This creates a package.json and installs Express. Now create an index.js file. That's all the setup we need.
A Minimal Server
Here's the skeleton for every Express app:
const express = require('express');
const app = express();
app.use(express.json()); // so we can parse JSON bodies
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
Run it with node index.js and you'll see the message. But the server doesn't do anything yet. Let's add some routes.
Defining Routes and Handling Requests
A REST API exposes endpoints that map to HTTP methods: GET, POST, PUT, DELETE. For our task list, we'll use an in-memory array. In a real app you'd use a database, but this keeps things focused.
Add this above the listen call:
let tasks = [
{ id: 1, title: 'Learn Express', done: false },
{ id: 2, title: 'Build an API', done: false }
];
// GET /tasks — return all tasks
app.get('/tasks', (req, res) => {
res.json(tasks);
});
// POST /tasks — add a new task
app.post('/tasks', (req, res) => {
const { title } = req.body;
if (!title) {
return res.status(400).json({ error: 'Title is required' });
}
const newTask = { id: tasks.length + 1, title, done: false };
tasks.push(newTask);
res.status(201).json(newTask);
});
// GET /tasks/:id — get a single task
app.get('/tasks/:id', (req, res) => {
const task = tasks.find(t => t.id === parseInt(req.params.id));
if (!task) {
return res.status(404).json({ error: 'Task not found' });
}
res.json(task);
});
That's a working API! Let's break down what's happening.
reqandresare the request and response objects.res.json()sends a JSON response automatically.req.paramsgives us route parameters (like:id).req.bodycontains parsed JSON data (thanks toexpress.json()).res.status()sets the HTTP status code.
Testing Your API
You can test with a tool like Postman, or just use curl in your terminal:
curl http://localhost:3000/tasks
You'll get the JSON array. For a POST request:
curl -X POST http://localhost:3000/tasks \
-H "Content-Type: application/json" \
-d '{"title": "Test the API"}'
You should see the new task returned with a 201 status.
Adding Middleware and Error Handling
Middleware functions run between the request and the route handler. They're perfect for logging, authentication, or custom error handling. Here's a simple logger:
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next(); // continue to the next middleware or route
});
Place this before your routes. Now every request gets logged.
For errors, you can add a catch-all handler after all routes:
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong' });
});
This is a 4-argument function, which Express recognizes as an error handler. It's a good practice to have one at the end.
What's Next?
You've built a basic REST API with Express. You know how to:
- Set up a server
- Define routes for different HTTP methods
- Send JSON responses
- Handle route parameters and request bodies
- Use middleware for logging and error handling
From here, you can explore:
- Using a database (like MongoDB or PostgreSQL) with an ORM
- Adding validation with libraries like Joi
- Organizing code with routers and controllers
- Protecting routes with JWT authentication
The key is to keep building—try adding a DELETE route, or a PUT to update tasks. You'll quickly get comfortable with the patterns.
Remember: every API you build will follow these same foundations. Master them, and you're well on your way to becoming a full-stack developer. Happy coding!