Back to Blog

Node.js / API / Backend

Building RESTful APIs with Node.js and Express

A comprehensive guide to building robust and scalable REST APIs using Node.js, Express, and best practices.

|12 min read

Introduction

Building RESTful APIs is a fundamental skill for backend developers. In this guide, we'll create a robust API using Node.js and Express.

Setting Up the Project

Initialize a new Node.js project:

mkdir my-api
cd my-api
npm init -y
npm install express cors helmet
npm install -D typescript @types/express @types/node

Basic Express Server

Create a simple Express server:

1 import express from 'express';
2 import cors from 'cors';
3 import helmet from 'helmet';
4
5 const app = express();
6 const PORT = process.env.PORT || 3000;
7
8 // Middleware
9 app.use(helmet());
10 app.use(cors());
11 app.use(express.json());
12
13 // Routes
14 app.get('/', (req, res) => {
15 res.json({ message: 'Welcome to the API' });
16 });
17
18 app.listen(PORT, () => {
19 console.log(`Server running on port ${PORT}`);
20 });

RESTful Routes

Implement CRUD operations:

1 // GET all items
2 app.get('/api/items', async (req, res) => {
3 const items = await Item.findAll();
4 res.json(items);
5 });
6
7 // GET single item
8 app.get('/api/items/:id', async (req, res) => {
9 const item = await Item.findById(req.params.id);
10 if (!item) {
11 return res.status(404).json({ error: 'Item not found' });
12 }
13 res.json(item);
14 });
15
16 // POST create item
17 app.post('/api/items', async (req, res) => {
18 const item = await Item.create(req.body);
19 res.status(201).json(item);
20 });
21
22 // PUT update item
23 app.put('/api/items/:id', async (req, res) => {
24 const item = await Item.update(req.params.id, req.body);
25 res.json(item);
26 });
27
28 // DELETE item
29 app.delete('/api/items/:id', async (req, res) => {
30 await Item.delete(req.params.id);
31 res.status(204).send();
32 });

Error Handling

Implement centralized error handling:

1 // Error handling middleware
2 app.use((err, req, res, next) => {
3 console.error(err.stack);
4 res.status(500).json({
5 error: 'Something went wrong!',
6 message: process.env.NODE_ENV === 'development' ? err.message : undefined
7 });
8 });

Validation

Validate request data:

1 import { z } from 'zod';
2
3 const itemSchema = z.object({
4 name: z.string().min(1),
5 price: z.number().positive(),
6 description: z.string().optional()
7 });
8
9 app.post('/api/items', async (req, res) => {
10 const result = itemSchema.safeParse(req.body);
11 if (!result.success) {
12 return res.status(400).json({ errors: result.error.errors });
13 }
14 // Create item...
15 });

Conclusion

You now have the foundation for building robust REST APIs with Node.js and Express. Remember to always validate input, handle errors gracefully, and follow REST conventions.

I've shipped APIs like this across fintech and SaaS products for over a decade — more about my background, or read Multi-Tenant SaaS Architecture Lessons for how these patterns scale to production.

Written by Erik Yuntantyo·Software Engineer·About me