ExpressREST APINode.js

Build Your First REST API with Express in 30 Minutes

A hands-on guide to creating a REST API with Express, covering routes, middleware, and error handling. No fluff, just code you can run today.

WebPrims Team2 September 20263 min read

What You'll Build

A REST API for managing a small collection of books. You'll get working endpoints for creating, reading, updating, and deleting records. The entire project takes less than thirty minutes to set up and run locally.

You need Node.js installed. Any version from 18 onward works fine. If you don't have it yet, grab the LTS release from the official site.

Project Setup

Create a new directory and initialize it.

mkdir books-api && cd books-api
npm init -y
npm install express

That's the whole setup. One dependency. Express handles routing, request parsing, and response formatting out of the box.

Create a file named server.js. This will hold the entire application. You can split things into separate files later, but for a first API, keeping everything in one place makes the flow easier to follow.

Your First Route

Open server.js and add the minimal Express boilerplate.

const express = require('express');
const app = express();

app.use(express.json());

const books = [
  { id: 1, title: 'The Pragmatic Programmer', author: 'Hunt & Thomas' },
  { id: 2, title: 'Clean Code', author: 'Robert C. Martin' }
];

app.get('/books', (req, res) => {
  res.json(books);
});

app.listen(3000, () => {
  console.log('API running on http://localhost:3000');
});

Run it with node server.js and visit http://localhost:3000/books in your browser. You'll see the JSON array. That's a working GET endpoint.

The express.json() middleware parses incoming request bodies. Without it, you can't read data sent in POST or PUT requests. Add it early in your middleware chain.

Adding CRUD Operations

A REST API lives and dies by its endpoints. Here's how the full set looks for the books resource.

  • GET /books — list all books
  • GET /books/:id — fetch a single book
  • POST /books — add a new book
  • PUT /books/:id — update an existing book
  • DELETE /books/:id — remove a book

Each route handler receives the request and response objects. You pull data from req.params, req.query, or req.body. Then you send back a response with the right status code.

Handling Requests and Responses

The route for fetching one book needs a parameter. Express exposes it through req.params.id.

app.get('/books/:id', (req, res) => {
  const book = books.find(b => b.id === parseInt(req.params.id));
  if (!book) {
    return res.status(404).json({ message: 'Book not found' });
  }
  res.json(book);
});

Notice the parseInt. URL parameters arrive as strings, and your data uses numbers. Always convert before comparing.

For creating a book, you read from req.body. The JSON middleware already parsed it for you.

app.post('/books', (req, res) => {
  const { title, author } = req.body;
  if (!title || !author) {
    return res.status(400).json({ message: 'Title and author are required' });
  }
  const newBook = { id: books.length + 1, title, author };
  books.push(newBook);
  res.status(201).json(newBook);
});

The 201 status tells the client a resource was created. Using the right status codes matters. Clients rely on them to decide what to do next.

Updating and deleting follow the same pattern. Find the item by ID, modify or remove it, then respond with the result.

Middleware and Error Handling

Express middleware runs between the request and your route handlers. It's useful for logging, authentication, or validation.

Here's a simple request logger that prints method and URL for every incoming request.

app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
});

The next() function passes control to the next middleware or route. Forget to call it and your request hangs forever.

For error handling, add a catch-all middleware at the end of your route definitions. It catches any errors thrown in your handlers.

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ message: 'Something went wrong' });
});

This four-argument signature is what Express recognizes as an error handler. The err parameter comes first, and the next parameter stays last even if you don't use it.

Testing Your API

You don't need fancy tooling to test. Use curl from your terminal.

curl http://localhost:3000/books
curl -X POST http://localhost:3000/books \
  -H "Content-Type: application/json" \
  -d '{"title":"Refactoring","author":"Martin Fowler"}'

Or install Postman or Insomnia if you prefer a visual interface. Both are free and work well for exploring APIs.

Where to Go From Here

You now have a functioning REST API. The next steps involve connecting it to a real database like PostgreSQL or MongoDB instead of an in-memory array. Add validation with a library like Zod or Joi. Implement pagination for list endpoints that return many records.

The pattern you just learned scales directly to larger applications. Routes, middleware, and error handling form the backbone of every Express project. Once you're comfortable with these three concepts, you can build almost anything.

ExpressREST APINode.js

Found this useful?

Share it with someone who is learning.