4.1 · Construir una API REST completa (CRUD)

Nivel 4 · API, autenticación y tiempo real

4.1Construir una API REST completa (CRUD)

Objetivo: Construir una API REST completa y bien estructurada (CRUD, recursos, métodos HTTP semánticos, códigos de estado, MVC) — un entregable central del back-end Node.
Tiempo estimado: 12 min · lectura autónoma · Si solo tienes 5 min: lee «Lo esencial en 30s» + el esquema.

Lo esencial en 30 segundos

  • REST = recursos + métodos HTTP : la URL designa el recurso en plural (/users), el método lleva la acción (GET leer, POST crear, PUT modificar, DELETE eliminar).
  • Estructurar en capas (MVC) : rutas (URL) → controladores (lógica) → modelos (datos) ; express.Router() agrupa las rutas por recurso.
  • Reflejo de Salim : devolver JSON con el código correcto (201 tras crear, 404 si no existe, 400 si es inválido) y versionar (/api/v1/).

Mini-caso hilado — Salim construye la API de productos en Argel

Salim, desarrollador junior en una startup en Argel, debe exponer el catálogo de productos al front : listar, mostrar un producto, crear, modificar, eliminar. Diseña primero sus endpoints REST (GET /api/v1/produits, GET /api/v1/produits/:id, POST, PUT, DELETE), separa rutas, controladores y datos, y agrupa las rutas en un express.Router() montado en la app. Cuando el front llama a su API, cada respuesta llega en JSON con el código de estado correcto. Primer hito del hilo : una API previsible que el front adivina sin documentación.

Este mismo caso vuelve en el curso, el esquema, el guion y el reto 48h — y continúa en 4.2, 4.3 y 4.4.

1. Los principios REST

REST es un estilo de arquitectura de API : se exponen recursos (usuarios, productos) identificados por URL claras en plural (/users, /produits), y se actúa sobre ellos con los métodos HTTP según su semántica : GET /users (listar), GET /users/:id (leer uno), POST /users (crear), PUT/PATCH /users/:id (modificar), DELETE /users/:id (eliminar). Como Salim, nunca se pone un verbo en la URL : no /getUsers, sino GET /users.

La API devuelve datos en JSON con los códigos de estado correctos : 200 éxito, 201 creado (tras POST), 204 sin contenido (tras DELETE), 400 petición inválida, 404 no encontrado, 500 error del servidor. Estas convenciones coherentes hacen la API previsible : el front adivina los endpoints en vez de memorizarlos uno por uno.

2. Estructurar en capas (MVC)

Una API que crece sin estructura se vuelve un plato de espaguetis. El patrón clásico es el MVC : los modelos (estructura y acceso a los datos), los controladores (lógica de tratamiento de cada petición), las rutas (definición de las URL y métodos, que delegan en los controladores). Carpetas típicas : routes/, controllers/, models/, más middlewares/, services/, config/.

Se usa el Router de Express (express.Router()) para agrupar las rutas por recurso en archivos separados (un router de productos, un router de pedidos), montados en la app. Esta separación hace el código comprensible, mantenible, testeable y evolutivo — y permite trabajar en equipo sin pisarse.

3. Las buenas prácticas de una API bien diseñada

Lo que separa una API profesional de una API que « funciona » : URL coherentes en plural, los métodos correctos para las acciones correctas, los códigos de estado correctos (nunca 200 para un error), una gestión de errores limpia (ver 4.4), la paginación de las listas, el versionado (/api/v1/...) para hacer evolucionar la API sin romper los clientes, y respuestas JSON estructuradas. Salim aplica esta check-list a cada endpoint antes de decir « está terminado ».

Error frecuente de interpretación: « Mi API funciona, así que está bien diseñada : el front recibe los datos, eso es lo esencial ». No. Una API puede devolver los datos correctos y ser incoherente (verbos en las URL, todo en POST, 200 para los errores, lógica amontonada en las rutas) — y esa deuda se paga en cuanto el front crece o llega un segundo cliente. Bien diseñado = previsible, mantenible, testeable — no solo funcional en la demo.
El recorrido de una petición en la API Rutas → controladores → modelos → respuesta Rutas URL + método(express.Router)Controladores Lógicade tratamientoModelos Datos (memoria,Mongoose, Prisma)Respuesta JSON + código deestado correcto
Rutas → controladores → modelos → respuesta
Versión en texto del esquema (SEO / lectores de pantalla / traducción): 1) Salim define sus endpoints REST : la URL designa el recurso en plural, el método HTTP lleva la acción. 2) Separa rutas (URL), controladores (lógica) y modelos (datos), con un router Express por recurso. 3) Cada respuesta sale en JSON con el código correcto : 201 tras crear, 404 si no existe, 400 si es inválido. Lección : previsible para el front, mantenible para el equipo.

🔎 Ejemplo concreto — 🔎 Ejemplo concreto — El CRUD REST de un recurso

La tabla de correspondencia que Salim muestra encima de su pantalla :

GET    /api/v1/produits      → listar (200)
GET    /api/v1/produits/:id  → leer uno (200, 404 si no existe)
POST   /api/v1/produits      → crear (201, 400 si es inválido)
PUT    /api/v1/produits/:id  → modificar (200, 404 si no existe)
DELETE /api/v1/produits/:id  → eliminar (204)

Lectura : cinco líneas, cinco parejas método + URL, cinco códigos esperados.

Lección : la acción la lleva el método HTTP, nunca la URL.

Vocabulario de la sección

API REST
Estilo de arquitectura de API web : exponer recursos (URL claras) manipulados por los métodos HTTP según su semántica, respuestas en JSON con los códigos de estado correctos.

Ejemplo sencillo: La API de productos de Salim : GET para leer, POST para crear, JSON en respuesta.

Lo que no es: un simple script que devuelve HTML mezclado con la lógica.

Reflejo: para cada endpoint, nombrar recurso, método y código esperado.

Recurso
Entidad expuesta por la API (productos, usuarios, pedidos), identificada por una URL clara en plural.

Ejemplo sencillo: El recurso productos de Salim vive bajo /api/v1/produits.

Lo que no es: una acción verbal como /creerProduit.

Reflejo: URL = nombre en plural, sin verbo.

MVC
Separación modelos (datos), controladores (lógica), rutas (URL) para un código mantenible y evolutivo.

Ejemplo sencillo: Salim coloca sus URL en routes/, su lógica en controllers/.

Lo que no es: todo el código amontonado en un solo archivo app.js.

Reflejo: una modificación toca una capa, no las tres.

express.Router()
Herramienta Express que agrupa las rutas de un recurso en un archivo separado, montado luego en la aplicación.

Ejemplo sencillo: El router de productos de Salim está montado con app.use('/api/v1/produits', routeur).

Lo que no es: la declaración de todas las rutas mezcladas en el archivo principal.

Reflejo: un archivo de rutas por recurso.

Código de estado
Número HTTP que comunica el resultado : 200 éxito, 201 creado, 204 sin contenido, 400 inválido, 404 no existe, 500 error del servidor.

Ejemplo sencillo: Salim devuelve 201 tras un POST con éxito, 404 para un producto desconocido.

Lo que no es: un 200 sistemático incluso en caso de error.

Reflejo: el cliente debe entender el resultado sin leer el cuerpo.

En la práctica — En práctica — Construir una API REST estructurada

  1. Diseñe los endpoints de un recurso según REST : GET /items (listar), GET /items/:id (leer), POST /items (crear), PUT /items/:id (modificar), DELETE /items/:id (eliminar).
  2. Estructure el proyecto en capas : routes/ (URL), controllers/ (lógica), models/ (datos) — como Salim para su catálogo.
  3. Use express.Router() para agrupar las rutas de un recurso en un archivo, montado en la app (app.use('/api/v1/items', itemsRouter)).
  4. Devuelva JSON con los códigos de estado correctos (201 tras crear, 404 si no se encuentra, 400 si los datos son inválidos) y prevea paginación y versionado.
Construye una API REST completa y bien estructurada (CRUD, recursos, métodos HTTP semánticos, códigos de estado, MVC) — un entregable central del back-end Node.

Guion listo para decir — presentar su API al front (30 s)

« Soy Salim : la API de productos sigue las convenciones REST — GET para leer, POST para crear, PUT para modificar, DELETE para eliminar, bajo /api/v1/produits, respuestas en JSON con los códigos correctos : 201 tras crear, 404 si no existe, 400 si es inválido. La estructura es en capas rutas, controladores, modelos, así que podremos añadir recursos sin romperlo todo. »

Para decir en revisión de código ; muestre la tabla de los cinco endpoints.

Modelo copiar-pegar — router CRUD Express (código probado)

const express = require('express');
const routeur = express.Router();

let produits = [];
let prochainId = 1;

// GET /api/v1/produits → listar (200)
routeur.get('/', (req, res) => {
  res.json(produits);
});

// GET /api/v1/produits/:id → leer uno (200 / 404)
routeur.get('/:id', (req, res) => {
  const produit = produits.find((p) => p.id === Number(req.params.id));
  if (!produit) return res.status(404).json({ erreur: 'Producto no encontrado' });
  res.json(produit);
});

// POST /api/v1/produits → crear (201 / 400)
routeur.post('/', (req, res) => {
  if (!req.body.nom) return res.status(400).json({ erreur: 'El campo nom es obligatorio' });
  const produit = { id: prochainId++, nom: req.body.nom };
  produits.push(produit);
  res.status(201).json(produit);
});

// PUT /api/v1/produits/:id → modificar (200 / 404)
routeur.put('/:id', (req, res) => {
  const produit = produits.find((p) => p.id === Number(req.params.id));
  if (!produit) return res.status(404).json({ erreur: 'Producto no encontrado' });
  if (req.body.nom) produit.nom = req.body.nom;
  res.json(produit);
});

// DELETE /api/v1/produits/:id → eliminar (204 / 404)
routeur.delete('/:id', (req, res) => {
  const index = produits.findIndex((p) => p.id === Number(req.params.id));
  if (index === -1) return res.status(404).json({ erreur: 'Producto no encontrado' });
  produits.splice(index, 1);
  res.status(204).end();
});

module.exports = routeur;
// Montaje (requiere express.json()) :
// const express = require('express');
// const app = express();
// app.use(express.json());
// app.use('/api/v1/produits', routeur);

Prototipo desechable

Basta una separación ligera (rutas + lógica), pero conserve las convenciones REST : no cuestan nada y evitan reescribir.

API real en equipo

Como Salim : capas completas (routes/, controllers/, models/, services/), un router por recurso, revisión de código sobre los estados.

API consumida por un móvil

Cuide paginación y respuestas JSON estables : el móvil cachea y sufre cada ruptura de contrato.

API que debe evolucionar

Versione desde el inicio (/api/v1/) : la v2 llegará, y sus clientes v1 no se romperán.

Prudencia: Una API expone su sistema al mundo : valide siempre las entradas (ver 4.4) y nunca devuelva detalles técnicos sensibles en los errores. Pruebe cada endpoint incluidos los casos de fallo (404, 400) antes de anunciar « está terminado ». Contenido pedagógico, ejemplos con datos ficticios.

✓ Buenas prácticas

  • URL = recurso en plural, acción = método HTTP.
  • Estructurar en capas en cuanto la API sea real.
  • Devolver el código de estado correcto cada vez.

✗ Errores frecuentes

  • Poner un verbo en la URL (/getProduits).
  • Devolver 200 para todo, incluso los errores.
  • Amontonar toda la lógica en los archivos de rutas.

Puntos clave

  • API REST : exponer RECURSOS (URL claras en plural) manipulados por los MÉTODOS HTTP según su semántica, en JSON con los CÓDIGOS DE ESTADO correctos.
  • CRUD REST : GET /produits (listar), GET /produits/:id (leer), POST (crear, 201), PUT (modificar), DELETE (eliminar, 204).
  • ESTRUCTURAR en capas (MVC) : models, controllers, routes + services/middlewares ; express.Router() agrupa las rutas por recurso.
  • Buenas prácticas : URL coherentes, códigos correctos, gestión de errores, paginación, versionado (/api/v1/). Previsible y profesional.

Reto 48h — aplica mañana

Construya el router CRUD completo de 1 recurso real (los 5 endpoints, códigos correctos) y pruebe cada ruta incluido el 404 y el 400.

Lista de salida de la sección
  • Puedo citar los 5 endpoints CRUD con sus códigos.
  • Sé separar rutas, controladores y modelos.
  • Probé 1 router completo, fallos incluidos.
Autoevaluación 1-5 : ¿mis URL llevan recursos sin verbo?¿mis códigos de estado son correctos en cada ruta?

Preguntas frecuentes

¿Qué distingue una API REST « bien diseñada » de una API que « funciona » simplemente?

Las convenciones y una estructura : URL coherentes sobre los recursos (sin verbo), métodos HTTP correctos según su semántica, códigos de estado correctos (201, 404, 400 — no 200 para todo), capas MVC en vez de espaguetis, gestión de errores limpia (4.4), validación de las entradas, respuestas JSON estructuradas, paginación y versionado (/api/v1/). Una API bien diseñada es previsible (se adivinan sus endpoints), mantenible y agradable de consumir — crucial porque está hecha para ser usada por otros.

¿Hay que estructurar en MVC desde el inicio, incluso para una API pequeña?

Adapte al proyecto, pero separe pronto : los proyectos casi siempre crecen y refactorizar un espagueti cuesta caro. Prototipo pequeño : separación ligera (rutas vs lógica, con express.Router()). API real : capas completas desde el inicio (routes/, controllers/, models/, services/) — comprensible, mantenible, testeable y colaborativa. Ni sobreingeniería para un ejercicio, ni cajón de sastre « porque es pequeño ».

Comprueba tu comprensión

En una API REST, ¿quién lleva la acción (crear, eliminar)?

Recursos adicionales (opcional, para ir más allá)

Examen del nivel 4Preguntas inéditas y más difíciles para validar tus conocimientos