Skip to content

Building a REST API With Node.js

REST is the dominant style for designing HTTP APIs. This lesson covers REST's core principles and how they map onto Express routes, HTTP verbs, and status codes.

What Makes an API RESTful?

REST (Representational State Transfer) organizes an API around resources, nouns like users, orders, products, each identified by a URL, and manipulated using standard HTTP verbs: GET to read, POST to create, PUT/PATCH to update, DELETE to remove.

A well-designed REST API is predictable: the same conventions (plural resource names, verb-based actions, consistent status codes) apply across every endpoint, which is what makes REST APIs easy for other developers to learn quickly.

import express from 'express';
const app = express();
app.use(express.json());

let products = [{ id: 1, name: 'Keyboard' }];

app.get('/products', (req, res) => res.json(products));

app.get('/products/:id', (req, res) => {
  const product = products.find((p) => p.id === Number(req.params.id));
  if (!product) return res.status(404).json({ error: 'Not found' });
  res.json(product);
});

app.post('/products', (req, res) => {
  const product = { id: products.length + 1, name: req.body.name };
  products.push(product);
  res.status(201).json(product);
});

Notice the pattern: /products (the collection) for listing and creating, /products/:id (a single resource) for reading, updating, or deleting one item.

REST Resource Conventions

GET    /products        -> list all products
GET    /products/:id    -> get one product
POST   /products        -> create a product
PUT    /products/:id    -> replace a product
PATCH  /products/:id    -> partially update a product
DELETE /products/:id    -> delete a product
  • Resource names are plural nouns (/products, not /product or /getProducts).
  • The HTTP verb, not the URL, expresses the action, avoid verbs in the path itself.
  • PUT conventionally replaces an entire resource; PATCH updates only the given fields.
  • Nested resources use nested paths, e.g. /orders/:orderId/items.

REST API Cheatsheet

Standard conventions used across most well-designed REST APIs.

Action Method + Path Success Status
List resources GET /products 200
Get one resource GET /products/:id 200
Create a resource POST /products 201
Replace a resource PUT /products/:id 200
Partially update PATCH /products/:id 200
Delete a resource DELETE /products/:id 204

REST APIs Should Be Stateless

Each request to a REST API should carry all the information the server needs to process it (an auth token, required parameters), without relying on server-side session state left over from a previous request. This makes REST APIs easy to scale horizontally, any server instance can handle any request.

Structuring an API Into Layers

As an API grows, separating concerns into layers, routes (HTTP-specific), controllers (translate requests to business logic calls), and services (the actual business logic), keeps the codebase testable and easy to navigate.

// routes/products.js -> defines the URLs and HTTP verbs
// controllers/productsController.js -> reads req, calls the service, sends res
// services/productService.js -> actual business logic, no knowledge of req/res

This separation means your business logic (in services) can be unit tested without spinning up an HTTP server at all.

Common Mistakes

  • Putting verbs in URLs, like /getProducts or /createProduct, instead of letting the HTTP method express the action.
  • Returning 200 OK for every response regardless of what actually happened, ignoring more precise status codes.
  • Mixing business logic directly into route handlers instead of separating it into a service layer.
  • Designing an API that depends on server-side session state between otherwise-stateless requests.

Key Takeaways

  • REST organizes APIs around resources (nouns), manipulated via standard HTTP verbs.
  • Consistent conventions (plural names, correct status codes) make an API predictable to use.
  • REST APIs should be stateless, each request carries everything the server needs.
  • Separating routes, controllers, and services keeps larger APIs maintainable and testable.

Pro Tip

Before writing a single route, sketch your API's resources and their URLs on paper first (/users, /users/:id/orders, ...). Getting the resource hierarchy right up front avoids painful, breaking URL changes later.