Build a REST API with Node.js and Express from Scratch
REST APIs are the backbone of modern web applications. Whether you're powering a mobile app, a single-page application, or a microservice, knowing how to build a clean and reliable API is an essential skill for any developer. In this tutorial, you'll build a fully functional REST API using Node.js and Express — step by step.
What You'll Need
- Node.js (v18 or later) installed on your machine
- A terminal or command prompt
- A code editor (VS Code recommended)
- Basic familiarity with JavaScript
Step 1: Initialize Your Project
Start by creating a new project directory and initializing it with npm:
mkdir my-api
cd my-api
npm init -y
Next, install Express:
npm install express
Step 2: Create Your Entry Point
Create a file called index.js in the root of your project. This will be the main entry point for your server:
const express = require('express');
const app = express();
const PORT = 3000;
app.use(express.json());
app.get('/', (req, res) => {
res.json({ message: 'API is running!' });
});
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
});
Run the server with node index.js and visit http://localhost:3000 in your browser or a tool like Postman.
Step 3: Define Your Routes
A REST API is organized around resources. For this example, we'll build a simple API for managing a list of tasks. Create a new file called routes/tasks.js:
const express = require('express');
const router = express.Router();
let tasks = [
{ id: 1, title: 'Learn Express', done: false },
{ id: 2, title: 'Build an API', done: false }
];
// GET all tasks
router.get('/', (req, res) => res.json(tasks));
// GET a single task
router.get('/: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);
});
// POST create a task
router.post('/', (req, res) => {
const task = { id: Date.now(), title: req.body.title, done: false };
tasks.push(task);
res.status(201).json(task);
});
// DELETE a task
router.delete('/:id', (req, res) => {
tasks = tasks.filter(t => t.id !== parseInt(req.params.id));
res.status(204).send();
});
module.exports = router;
Step 4: Register Your Router
Back in index.js, import and use the tasks router:
const tasksRouter = require('./routes/tasks');
app.use('/api/tasks', tasksRouter);
Step 5: Add Basic Error Handling
Good APIs handle errors gracefully. Add a catch-all error handler at the bottom of index.js:
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong' });
});
HTTP Method Summary
| Method | Endpoint | Action |
|---|---|---|
| GET | /api/tasks | Retrieve all tasks |
| GET | /api/tasks/:id | Retrieve a single task |
| POST | /api/tasks | Create a new task |
| DELETE | /api/tasks/:id | Delete a task |
Next Steps
Now that your API is running, here are some natural next steps to level it up:
- Connect a real database using MongoDB (with Mongoose) or PostgreSQL (with Prisma)
- Add authentication using JWT tokens
- Validate incoming request data with a library like Zod or Joi
- Document your API with Swagger/OpenAPI
Building APIs becomes intuitive quickly once you understand the fundamentals of routing, middleware, and HTTP semantics. Keep experimenting!