Node.js REST API
A Node.js REST API lets other programs, such as a React front end or a mobile app, read and change data over HTTP. In this chapter you will build a complete CRUD (Create, Read, Update, Delete) API for books with Express, storing data in memory to keep the focus on the API design.
REST Conventions
- GET /api/books — list all books (200)
- GET /api/books/:id — get one book (200, or 404)
- POST /api/books — create a book (201 with the new book)
- PUT /api/books/:id — update a book (200, or 404)
- DELETE /api/books/:id — delete a book (204 no content)
- Invalid input returns 400 with an error message
The Complete API
import express from 'express';
const app = express();
app.use(express.json());
let books = [
{ id: 1, title: 'Clean Code', author: 'Robert C. Martin' },
{ id: 2, title: 'Eloquent JavaScript', author: 'Marijn Haverbeke' },
];
let nextId = 3;
const findBook = (id) => books.find((b) => b.id === Number(id));
app.get('/api/books', (req, res) => res.json(books));
app.get('/api/books/:id', (req, res) => {
const book = findBook(req.params.id);
if (!book) return res.status(404).json({ error: 'Book not found' });
res.json(book);
});
app.post('/api/books', (req, res) => {
const { title, author } = req.body;
if (!title || !author) return res.status(400).json({ error: 'title and author are required' });
const book = { id: nextId++, title, author };
books.push(book);
res.status(201).json(book);
});
app.put('/api/books/:id', (req, res) => {
const book = findBook(req.params.id);
if (!book) return res.status(404).json({ error: 'Book not found' });
Object.assign(book, { title: req.body.title ?? book.title, author: req.body.author ?? book.author });
res.json(book);
});
app.delete('/api/books/:id', (req, res) => {
const before = books.length;
books = books.filter((b) => b.id !== Number(req.params.id));
if (books.length === before) return res.status(404).json({ error: 'Book not found' });
res.status(204).end();
});
app.listen(3000, () => console.log('Books API on http://localhost:3000'));Books API on http://localhost:3000
Testing the API with curl
curl is available in most terminals (including Windows 10+). You can also use tools like Postman, Insomnia or the VS Code REST Client extension.
curl http://localhost:3000/api/books/1
curl -X POST http://localhost:3000/api/books \
-H "Content-Type: application/json" \
-d '{"title":"Refactoring","author":"Martin Fowler"}'
curl -X DELETE http://localhost:3000/api/books/2 -i{"id":1,"title":"Clean Code","author":"Robert C. Martin"}
{"id":3,"title":"Refactoring","author":"Martin Fowler"}
HTTP/1.1 204 No ContentConnecting to a Database
In-memory arrays reset when the server restarts. Real APIs store data in a database. The route structure stays the same; only the data access changes. For example with MongoDB (via Mongoose) you would write const book = await Book.findById(req.params.id), and with MySQL or PostgreSQL you might use a query builder or ORM such as Prisma or Knex.
API Design Tips
- Version your API (/api/v1/...) so you can change it later without breaking clients.
- Return consistent JSON error objects.
- Paginate large lists with ?page= and ?limit= query parameters.
- Validate input with a library such as zod or express-validator.
Frequently asked questions
What is a REST API in Node.js?
An HTTP server, usually built with Express, that exposes resources at URLs and uses HTTP methods (GET, POST, PUT, DELETE) to read and change them, typically exchanging JSON.
What is the difference between PUT and PATCH?
PUT traditionally replaces a whole resource, while PATCH applies a partial update. Many APIs accept partial data for PUT too, but following the convention makes your API clearer.
Which status code should a POST request return?
201 Created, usually with the new resource in the body and optionally a Location header pointing to it.