Lección 1 de 12 · Lectura y práctica
Principios de arquitectura REST
Principios de Arquitectura REST - APIs RESTful con Node.js y Express Principios de Arquitectura REST En esta lección exploraremos los fundamentos teóricos y prácticos que rigen la arquitectura REST (Representational State.
Del concepto a la práctica
Taller de esta lección
Una decisión REST útil es modelar aquello que existe, no la acción que se quiere ejecutar. En una biblioteca, el recurso es un préstamo; “devolver” puede representarse modificando su estado, no creando una ruta verbal como /devolverLibro.
Ejemplo resuelto
Para PATCH /prestamos/42 con { "devuelto": true }, una respuesta válida puede ser 200 y devolver el préstamo actualizado. Si el identificador 42 no existe, corresponde 404; si el cuerpo no contiene un booleano, 400. La representación sigue siendo un préstamo en todos los casos.
Pruébalo
Define
GET /librospara colección yGET /libros/7para elemento.Define
POST /prestamospara crear una relación entre usuario y libro.Decide qué campos devuelve cada respuesta y cuál es el estado de una creación.
Escribe un caso de inexistencia y otro de entrada inválida.
Error frecuente: usar POST /prestarLibro para todo. Corrígelo separando recurso, método y transición de estado; así el cliente puede comprender el contrato sin conocer una frase interna.
Comprueba tu resultado
Tu diseño es verificable si contiene tres rutas con sustantivos, diferencia colección de elemento, asigna 201 a la creación y reserva 404 para un identificador ausente. El caso inválido no debe modificar ningún préstamo.

Mapa de prácticaEl navegador envía una solicitud a la API. El servidor valida la operación y consulta los datos; después devuelve una respuesta que el navegador puede mostrar. La base de datos se comunica con el servidor y no directamente con el navegador.
Ver la infografía en tamaño completo ↗Principios de Arquitectura REST
En esta lección exploraremos los fundamentos teóricos y prácticos que rigen la arquitectura REST (Representational State Transfer). Comprender estos principios es esencial para diseñar APIs robustas, escalables y mantenibles con Node.js y Express.
¿Qué es REST?
REST no es un protocolo ni un formato específico, sino un estilo arquitectónico definido por Roy Fielding en su tesis doctoral en el año 2000. Fielding, uno de los principales autores de HTTP, diseñó REST como una forma de aplicar los principios de HTTP de manera más rigurosa a los servicios web.
REST es un estilo arquitectónico, no una especificación. Esto significa que existen diferentes grados de "pureza" REST. Una API puede ser más o menos RESTful dependiendo de cuánto adhiera a sus principios fundamentales.
Los 6 Principios Fundamentales de REST
1. Arquitectura Cliente-Servidor
El principio más básico establece una clara separación de responsabilidades. El cliente se encarga de la interfaz de usuario y la presentación, mientras que el servidor gestiona los datos y la lógica de negocio. Esta separación permite que ambos evolucionen de forma independiente.
2. Sistema de Capas
El cliente no necesita saber si está comunicándose directamente con el servidor final o con un intermediario (proxy, balanceador de carga, caché). Esta opacidad permite añadir capas de infraestructura sin modificar el código del cliente.
// Estructura típica con capas en Express
app.use('/api/v1', cacheMiddleware); // Capa de caché
app.use('/api/v1', rateLimitMiddleware); // Capa de limitación
app.use('/api/v1', authMiddleware); // Capa de autenticación
app.use('/api/v1', routes); // Capa de rutas (lógica de negocio)
app.use('/api/v1', controller); // Capa de controladores
app.use('/api/v1', model); // Capa de datos
3. Sin Estado (Stateless)
Quizás el principio más crítico y frecuentemente malinterpretado. Cada petición del cliente al servidor debe contener toda la información necesaria para procesar la solicitud. El servidor no debe almacenar estado de sesión del cliente entre peticiones.
4. Interfaz Uniforme
Este principio establece que todos los recursos deben ser accesibles a través de una interfaz genérica. Incluye cuatro sub-restricciones:
- Identificación de recursos: Cada recurso tiene un identificador único (URI)
- Manipulación mediante representaciones: El cliente recibe representaciones del recurso (JSON, XML)
- Mensajes autodescriptivos: Cada mensaje contiene toda la información necesaria
- Hipermedia como motor de estado (HATEOAS): Las respuestas incluyen enlaces a acciones relacionadas
5. Cacheable
Las respuestas deben indicarse como cacheables o no-cacheables. Una caché bien implementada puede mejorar significativamente el rendimiento. HTTP proporciona headers específicos para esto.
// Ejemplo de configuración de caché en Express
app.get('/api/v1/productos', (req, res) => {
// Indicar que la respuesta es cacheable por 1 hora
res.set('Cache-Control', 'public, max-age=3600');
res.json(productos);
});
app.get('/api/v1/usuarios/:id', (req, res) => {
// Indicar que NO debe cachearse (datos sensibles)
res.set('Cache-Control', 'private, no-cache');
res.json(usuario);
});
6. Código bajo Demanda (Opcional)
Los servidores pueden extender la funcionalidad del cliente transfiriendo código ejecutable (JavaScript en el navegador, por ejemplo). Este principio es opcional y rara vez se implementa completamente en APIs REST modernas.
Recursos y URIs: El Corazón de REST
En REST, todo es un recurso. Un usuario, un producto, una transacción, incluso una búsqueda son recursos. Cada recurso debe tener un identificador único y persistente: el URI (Uniform Resource Identifier).
Un URI representa un recurso, no una acción. Esto es fundamental. "Obtener usuario con ID 5" no es
/obtenerUsuario?id=5, sino /usuarios/5.
Buenas Prácticas para URIs
| ❌ Incorrecto | ✅ Correcto | Razón |
|---|---|---|
/getUsuarios |
/usuarios |
Los URIs no contienen verbos |
/api/get_data |
/usuarios |
Usa sustantivos plurales, no "data" |
/usuarios/5/productos |
/productos?usuario=5 |
Evita anidamiento profundo |
/Usuarios |
/usuarios |
Usa minúsculas consistentes |
https://api.tudominio.com/v1/recurso/{id}/subrecurso. La versión en la URL permite evolucionar tu API sin romper clientes existentes.
Métodos HTTP y sus Semánticas
Una de las elegancia de REST es usar los métodos HTTP existentes con su semántica original. No se trata solo de convenciones: cada método tiene una significado específico que debe respetarse.
| Método | Semántica | Idempotente | Seguro | Uso común en Express |
|---|---|---|---|---|
| GET | Obtener recurso | ✅ Sí | ✅ Sí | Lectura sin modificación |
| POST | Crear recurso | ❌ No | ❌ No | Crear nuevos elementos |
| PUT | Reemplazar recurso | ✅ Sí | ❌ No | Actualización completa |
| PATCH | Modificar parcialmente | ❌ No | ❌ No | Actualización parcial |
| DELETE | Eliminar recurso | ✅ Sí | ❌ No | Eliminación de recursos |
Códigos de Estado HTTP
Los códigos de estado son la forma en que el servidor comunica el resultado de una petición. Usarlos correctamente es crucial para una API RESTful profesional.
- 2xx - Éxito: La petición fue recibida y procesada correctamente.
- 3xx - Redirección: Se requieren acciones adicionales para completar la petición.
- 4xx - Error del cliente: La petición tiene problemas de formato o es inválida.
- 5xx - Error del servidor: El servidor falló al procesar una petición válida.
// Ejemplo de uso correcto de códigos de estado en Express
// GET /usuarios/5 - Usuario encontrado
res.status(200).json(usuario);
// POST /usuarios - Usuario creado exitosamente
res.status(201).json(nuevoUsuario);
// GET /usuarios/999 - Usuario no encontrado
res.status(404).json({ error: 'Usuario no encontrado' });
// POST /usuarios - Datos inválidos
res.status(400).json({ error: 'El campo "email" es requerido' });
// GET /usuarios - Error interno del servidor
res.status(500).json({ error: 'Error interno del servidor' });
Ver más códigos de estado comunes en APIs REST
Códigos de éxito:
200- OK (respuesta estándar)201- Created (recurso creado)204- No Content (sin cuerpo de respuesta)
Códigos de error de cliente:
400- Bad Request (sintaxis inválida)401- Unauthorized (autenticación requerida)403- Forbidden (sin permisos)404- Not Found (recurso inexistente)409- Conflict (conflicto de estado)422- Unprocessable Entity (validación fallida)
Códigos de error de servidor:
500- Internal Server Error503- Service Unavailable
HATEOAS: Navegación mediante Hipermedia
HATEOAS (Hypermedia as the Engine of Application State) es quizás el principio de REST más avanzado y menos implementado. Significa que las respuestas de tu API deben incluir enlaces que indiquen las acciones posibles desde ese estado.
// Ejemplo de respuesta con HATEOAS
{
"id": 5,
"nombre": "Juan Pérez",
"email": "juan@ejemplo.com",
"links": [
{ "rel": "self", "href": "/usuarios/5", "method": "GET" },
{ "rel": "actualizar", "href": "/usuarios/5", "method": "PUT" },
{ "rel": "eliminar", "href": "/usuarios/5", "method": "DELETE" },
{ "rel": "pedidos", "href": "/usuarios/5/pedidos", "method": "GET" }
]
}
"La interfaz uniforme de REST se define mediante la disponibilidad de recursos de hipermedia en las representaciones devueltas." — Roy Fielding
Ejemplo Práctico: API RESTful con Express
Veamos cómo implementar una API que siga los principios REST utilizando Express:
const express = require('express');
const app = express();
app.use(express.json());
// Base de datos simulada
let usuarios = [
{ id: 1, nombre: 'Ana García', email: 'ana@ejemplo.com' },
{ id: 2, nombre: 'Carlos López', email: 'carlos@ejemplo.com' }
];
// GET /usuarios - Listar todos (colección)
app.get('/api/v1/usuarios', (req, res) => {
res.status(200).json({
datos: usuarios,
total: usuarios.length
});
});
// GET /usuarios/:id - Obtener uno (recurso individual)
app.get('/api/v1/usuarios/:id', (req, res) => {
const usuario = usuarios.find(u => u.id === parseInt(req.params.id));
if (!usuario) {
return res.status(404).json({ error: 'Usuario no encontrado' });
}
res.status(200).json(usuario);
});
// POST /usuarios - Crear nuevo
app.post('/api/v1/usuarios', (req, res) => {
const { nombre, email } = req.body;
if (!nombre || !email) {
return res.status(400).json({ error: 'Nombre y email son requeridos' });
}
const nuevoUsuario = {
id: usuarios.length + 1,
nombre,
email
};
usuarios.push(nuevoUsuario);
res.status(201).json(nuevoUsuario);
});
// PUT /usuarios/:id - Reemplazar completamente
app.put('/api/v1/usuarios/:id', (req, res) => {
const index = usuarios.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: 'Usuario no encontrado' });
}
const { nombre, email } = req.body;
if (!nombre || !email) {
return res.status(400).json({ error: 'Nombre y email son requeridos' });
}
usuarios[index] = { id: parseInt(req.params.id), nombre, email };
res.status(200).json(usuarios[index]);
});
// DELETE /usuarios/:id - Eliminar
app.delete('/api/v1/usuarios/:id', (req, res) => {
const index = usuarios.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: 'Usuario no encontrado' });
}
usuarios.splice(index, 1);
res.status(204).send(); // 204 = éxito sin contenido
});
app.listen(3000, () => console.log('API RESTful ejecutándose en puerto 3000'));
¿Cuál de las siguientes afirmaciones sobre los principios REST es INCORRECTA?
- A) La arquitectura cliente-servidor establece separación de responsabilidades
- B) Las APIs REST deben ser obligatoriamente stateful para mantener sesiones
- C) Los códigos de estado HTTP comunican el resultado de las peticiones
- D) DELETE es idempotente mientras que POST no lo es
Conclusión
Los principios de arquitectura REST proporcionan una base sólida para diseñar APIs HTTP que son escalables, simples y mantenibles. Aunque en la práctica muchas APIs "RESTful" no siguen todos los principios al 100%, comprenderlos te permitirá tomar decisiones informadas sobre cuándo adherirte estrictamente y cuándo hacer compromisos pragmáticos.
Práctica acompañada: Una interfaz web de principio a fin
Estado, formularios y una API pequeña. Usa este cuaderno como práctica complementaria de la ruta; el material original de la lección continúa siendo tu referencia.
Práctica: cuatro pruebas de comportamiento
Prueba un título normal, solo espacios, 121 caracteres y una falla de red simulada. Registra la respuesta y el estado de la interfaz. Repite usando solo teclado: debes llegar al campo, enviarlo y encontrar el error sin usar el ratón.
Después agrega una segunda tarea y cambia el orden de la lista. Comprueba que cada botón sigue actuando sobre el elemento correcto. Si trabajas con microservicios, dibuja qué servicio posee el dato y qué ocurre si la dependencia no responde. No necesitas una infraestructura distribuida para aprender a definir tiempos de espera y errores comprensibles.
Comprueba tu entrega
Entrega el código, el contrato de API y evidencia de las cuatro pruebas. Indica si los datos se guardan o desaparecen al recargar. Una demostración en memoria debe decirlo para que nadie confunda un prototipo con almacenamiento persistente.
Sigue con Construcción de APIs RESTful con Node.js y Express
Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.
Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.