← Node & Express

REST APIs

What is a REST API and what are its fundamental principles?

Show answer — try answering out loud first

REST is an architectural style for designing APIs over HTTP. Its central ideas are: exposing resources identified by URLs (using nouns, not verbs), operating on them with the HTTP verbs (GET, POST, PUT, PATCH, DELETE), being stateless (each request carries all the necessary information) and using representations of the resources, usually in JSON.

REST (Representational State Transfer) is a way of organizing how the client and the server communicate. Instead of inventing names for each action, we follow clear conventions:

  • Resources identified by URLs. A resource is a "thing" in your system: a user, a product, an order. Each resource has a URL that identifies it. The URL uses nouns, not verbs. The action is indicated by the HTTP verb, not the URL.
    • Correct: GET /usuarios, GET /usuarios/42
    • Incorrect: GET /getUsuarios, POST /crearUsuario
  • HTTP verbs for the actions. The same resource /usuarios/42 changes its behavior depending on the verb: GET reads it, PUT replaces it, DELETE deletes it.
  • Stateless. The server does not keep a session between requests. Each request must carry everything needed to be understood on its own (for example, an authentication token in the headers). This makes the API scale better: any server can handle any request.
  • Representations. The client does not receive the server's internal object, but a representation of that resource. The most common one is JSON. The same resource could be represented in different formats, but JSON is the de facto standard.

In short: noun URLs + HTTP verbs + stateless + JSON.

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

// Middleware so Express understands JSON bodies in the requests
app.use(express.json());

// In-memory "database" just for the example
let usuarios = [
  { id: 1, nombre: 'Ana' },
  { id: 2, nombre: 'Luis' },
];

// Resource: /usuarios (plural noun, NOT /getUsuarios)

// GET /usuarios -> reads the whole collection
app.get('/usuarios', (req, res) => {
  res.json(usuarios); // Returns a JSON representation
});

// GET /usuarios/:id -> reads a specific resource
app.get('/usuarios/:id', (req, res) => {
  const id = Number(req.params.id);
  const usuario = usuarios.find((u) => u.id === id);

  if (!usuario) {
    return res.status(404).json({ error: 'Usuario no encontrado' });
  }
  res.json(usuario);
});

// POST /usuarios -> creates a new resource in the collection
app.post('/usuarios', (req, res) => {
  const nuevo = { id: usuarios.length + 1, nombre: req.body.nombre };
  usuarios.push(nuevo);
  res.status(201).json(nuevo); // 201 = created
});

app.listen(3000, () => console.log('API escuchando en el puerto 3000'));

Testing the API with curl:

# Read all the users
curl http://localhost:3000/usuarios

# Read a specific user
curl http://localhost:3000/usuarios/1

# Create a new user
curl -X POST http://localhost:3000/usuarios \
  -H "Content-Type: application/json" \
  -d '{"nombre":"Marta"}'

Putting verbs in the URL instead of nouns: POST /crearUsuario, GET /obtenerUsuarios, POST /borrarUsuario/5. This breaks the idea of REST, because the verb is already supplied by the HTTP method. The URL should name the resource (/usuarios), and the HTTP method indicates what you do with it.

Another frequent mistake is assuming the server "remembers" the client between requests (keeping in the server's memory who is logged in). REST is stateless: each request must include on its own what it needs, such as the authentication token.

"REST is an architectural style for APIs over HTTP. The central idea is that I expose resources identified by URLs, and those URLs use nouns, not verbs: for example /usuarios, not /getUsuarios. The action is determined by the HTTP verb: GET to read, POST to create, PUT or PATCH to update and DELETE to delete. Another key principle is that it's stateless: the server doesn't keep a session between requests, so each request carries all the information it needs, such as the authentication token in the headers. And the client works with representations of the resource, which are usually JSON. Following these conventions the API stays predictable and easy to consume."

Quick challenge

You have an API that manages "products". A colleague defined these endpoints:

How would you rewrite them following the REST principles?

See answer

Using a noun for the resource (/productos) and letting the HTTP verb indicate the action:

  • GET /obtenerProductos -> GET /productos
  • POST /nuevoProducto -> POST /productos
  • POST /eliminarProducto/10 -> DELETE /productos/10

The URL names the resource; the HTTP method says what to do with it.