Desarrollo Web Backend
Parte 1
Clase 6 — Cliente-servidor, APIs REST y Express
Objetivos de aprendizaje
Al terminar esta clase, podrás levantar tu propio servidor y diseñar APIs limpias que cualquier frontend pueda consumir.
Cliente-Servidor
Entender cómo se comunican frontend y backend a través de HTTP.
APIs REST
Diseñar endpoints siguiendo convenciones REST y elegir verbos y códigos.
Arquitecturas
Diferenciar monolito, microservicios y serverless, y saber cuándo usar cada uno.
Node.js + Express
Crear un servidor con rutas, middleware y un CRUD completo.
El modelo cliente-servidor
Hasta ahora trabajamos el frontend: lo que el usuario ve. Detrás hay un backend que hace el trabajo pesado.
Frontend
El salón: la carta, el mesero, la presentación del plato. React, HTML, CSS — todo en el navegador del usuario.
Backend
La cocina: recibe pedidos, procesa ingredientes, prepara la comida. Vive en un servidor remoto, lejos del usuario.
Base de datos
La despensa: almacena los ingredientes. El backend la consulta, el frontend nunca la toca directamente.
Por qué separarlos
Seguridad (la lógica crítica nunca llega al cliente), reutilización (una API sirve a web, móvil y otros sistemas) y escalabilidad (puedes desplegar y escalar cada parte por separado).
Qué hace exactamente un backend
Cinco responsabilidades que rara vez deberían vivir en el frontend.
💰 Lógica de negocio
Calcular precios con impuestos, aplicar descuentos, validar reglas que cambian sin redeploy del frontend.
💾 Persistencia
Hablar con la base de datos para guardar, leer, actualizar y borrar datos. Único punto de acceso a esos datos.
🔐 Autenticación y autorización
¿Quién es el usuario? (autenticación) ¿Qué le dejas hacer? (autorización). Tokens, sesiones, permisos.
📧 Tareas en segundo plano
Enviar emails, procesar pagos, generar PDFs, sincronizar datos. Todo lo que el usuario no puede esperar mirando una pantalla.
🔌 Integración con otros servicios
Llamar a APIs externas (Stripe, OpenAI, AWS), agregar datos de varias fuentes y devolver una respuesta unificada al frontend.
HTTP es stateless: cada petición es una isla
El servidor no recuerda nada entre peticiones. Cada request lleva consigo todo lo que necesita: URL, headers, body, credenciales. Esto es lo que permite que un backend sirva a millones de clientes en paralelo.
Ventajas
- • Escalado horizontal: añadir servidores no es un drama
- • Caché: responses idénticas se pueden guardar
- • Resiliencia: si un servidor cae, otro toma la petición
Implicaciones
- • Login: en cada request hay que enviar un token o cookie
- • Estado del usuario vive en la base de datos, no en memoria
- • Las sesiones se modelan, no son automáticas
📚Material complementario▾
HTTP — anatomía de una petición y una respuesta
Toda la web habla este idioma. Una petición tiene cuatro partes y una respuesta, también.
GET /api/productos?limit=10 HTTP/1.1Host: api.tienda.comAccept: application/jsonAuthorization: Bearer eyJhbGc...User-Agent: Mozilla/5.0 ...// (sin body en GET)- • Línea de petición: verbo, ruta, versión
- • Headers: metadatos (auth, formato, host)
- • Body: datos (en POST/PUT/PATCH)
HTTP/1.1 200 OKContent-Type: application/jsonContent-Length: 142Cache-Control: max-age=60{ "productos": [ { "id": 1, "nombre": "Laptop" }] }- • Status line: versión, código, frase
- • Headers: tipo de contenido, caché, CORS
- • Body: el dato pedido (JSON, HTML, binario)
Headers que verás todos los días
| Header | Para qué sirve |
|---|---|
| Content-Type | Formato del body: application/json, text/html, multipart/form-data... |
| Accept | Formato que el cliente espera de respuesta. |
| Authorization | Credenciales: Bearer <token>, Basic .... |
| Cookie / Set-Cookie | Sesiones, preferencias y tracking persistentes en el navegador. |
| Cache-Control | Cuánto tiempo vale guardar la respuesta en caché. |
| User-Agent | Quién hace la petición: navegador, librería, bot. |
| Access-Control-Allow-Origin | CORS: qué orígenes pueden consumir esta API desde el navegador. |
📚Material complementario▾
API: el contrato entre dos sistemas
API(Application Programming Interface) es la forma en la que un programa expone sus capacidades a otro. Define qué se puede pedir, cómo y qué te van a devolver.
Web API / REST
Recursos accesibles vía HTTP, JSON como formato. Lo más común hoy.
GraphQL
Un solo endpoint, el cliente describe la forma exacta de los datos que necesita.
gRPC / WebSocket
Comunicación binaria de baja latencia y conexiones bidireccionales en tiempo real.
En esta clase
Nos centramos en REST sobre HTTP con JSON: es lo que más vas a encontrar en el mundo real y lo que casi todo framework soporta de fábrica.
JSON — el formato común de la web
JavaScript Object Notation. Texto plano, legible para humanos y trivial de parsear en cualquier lenguaje. Lo usan REST, configuraciones, logs y casi todo.
{ "id": 42, "nombre": "Laptop", "disponible": true, "etiquetas": ["nuevo", "oferta"], "stock": null, "specs": { "ram": 16, "ssd": 512 }}Tipos disponibles
string, number, boolean, null, array y object. No hay funciones, fechas ni undefined: las fechas viajan como string ISO.
Reglas estrictas
Claves entre comillas dobles. Sin trailing commas. Sin comentarios. Una coma de más rompe el parser.
En Node
JSON.stringify(obj) serializa,JSON.parse(texto) deserializa. Express lo hace por ti conexpress.json().
📚Material complementario▾
REST — Representational State Transfer
REST no es un estándar formal: es unestilo arquitectónico que Roy Fielding describió en 2000 y que la industria adoptó como convención común.
Principios clave
- • Recursos: cada cosa tiene una URL única
- • Verbos HTTP: la acción la indica el método
- • Stateless: cada petición es independiente
- • Representaciones: JSON, XML, HTML... el cliente elige
- • Capas: cachés y proxies entre cliente y servidor
Por qué se impuso
- • Aprovecha HTTP tal cual, sin protocolos extra
- • Cualquier cliente (browser, móvil, curl) lo puede usar
- • Cacheable de fábrica con headers HTTP
- • Convenciones claras → menos discusiones de equipo
- • Tooling masivo: Postman, Swagger, librerías para todo
Recursos: las "cosas" de tu API
En REST piensas en sustantivos: productos, usuarios, pedidos. Cada recurso tiene una URL y se opera con verbos HTTP.
// Colección: lista de productosGET /api/productosPOST /api/productos// Recurso individual: producto 42GET /api/productos/42PUT /api/productos/42PATCH /api/productos/42DELETE /api/productos/42// Sub-recurso: reviews del producto 42GET /api/productos/42/reviewsPOST /api/productos/42/reviewsPath params
Identifican un recurso concreto:/productos/42.
Query params
Filtros, paginación, búsqueda:?categoria=ropa&page=2&limit=20.
Body
Datos para crear o actualizar (POST, PUT, PATCH). Suele ser JSON.
Diseño RESTful — bien vs. mal
Las reglas de oro que separan una API agradable de una pesadilla mantenible.
GET /api/v1/productosGET /api/v1/productos/42POST /api/v1/productosPATCH /api/v1/productos/42DELETE /api/v1/productos/42GET /api/v1/usuarios/7/pedidosGET /api/v1/tipos-productoGET /api/obtenerProductosGET /api/productoPOST /api/crearNuevoProductoGET /api/producto/eliminar/42POST /api/PRODUCTOS_v2/UPDATEGET /api/usuario_pedidos?uid=7GET /api/tipoProductoReglas de oro
- • Sustantivos en plural:
/usuarios, no/obtenerUsuario - • Jerarquía con
/:/usuarios/7/pedidos - • kebab-case en rutas multi-palabra:
/tipos-producto - • Versiona la API:
/api/v1/...permite evolucionar sin romper clientes - • GET nunca modifica datos. Si un buscador rastrea, ¿borraría tus recursos?
📚Material complementario▾
Verbos HTTP — qué hace cada uno
Pulsa cualquier verbo para ver qué pasa por la red en cada caso.
Uso: Leer un recurso o lista de recursos. No modifica datos.
Idempotente: Sí — repetirlo da el mismo resultado.
// PeticiónGET /api/productos/42 HTTP/1.1Host: api.tienda.comAccept: application/json// RespuestaHTTP/1.1 200 OKContent-Type: application/json { "id": 42, "nombre": "Laptop", "precio": 999 }Uso: Crear un recurso nuevo en una colección.
Idempotente: No — cada llamada crea un recurso distinto.
// PeticiónPOST /api/productos HTTP/1.1Host: api.tienda.comContent-Type: application/json { "nombre": "Teclado", "precio": 79 }// RespuestaHTTP/1.1 201 CreatedLocation: /api/productos/43 { "id": 43, "nombre": "Teclado", "precio": 79 }Uso: Reemplazar por completo un recurso existente.
Idempotente: Sí — repetirlo deja el recurso en el mismo estado.
// PeticiónPUT /api/productos/42 HTTP/1.1Host: api.tienda.comContent-Type: application/json { "nombre": "Laptop Pro", "precio": 1299 }// RespuestaHTTP/1.1 200 OKContent-Type: application/json { "id": 42, "nombre": "Laptop Pro", "precio": 1299 }Uso: Actualizar parcialmente: solo los campos enviados.
Idempotente: Generalmente sí (depende de la implementación).
// PeticiónPATCH /api/productos/42 HTTP/1.1Host: api.tienda.comContent-Type: application/json { "precio": 899 }// RespuestaHTTP/1.1 200 OKContent-Type: application/json { "id": 42, "nombre": "Laptop", "precio": 899 }Uso: Eliminar un recurso.
Idempotente: Sí — borrar lo que ya no existe sigue dejándolo borrado.
// PeticiónDELETE /api/productos/42 HTTP/1.1Host: api.tienda.com// RespuestaHTTP/1.1 204 No Content(sin cuerpo)Códigos de estado — el "rendir cuentas" del servidor
Tres dígitos que resumen el resultado. El primero es el más importante.
1xx · Info
Raras de ver. 100 Continue, 101 Switching Protocols(WebSockets).
2xx · Éxito
200 OK— todo bien201 Created— recurso creado204 No Content— bien, sin body
4xx · Cliente
400 Bad Request401 Unauthorized403 Forbidden404 Not Found409 Conflict422 Unprocessable429 Too Many Requests
5xx · Servidor
500 Internal Error502 Bad Gateway503 Service Unavailable504 Gateway Timeout
Diferenciar 401 vs 403
401 Unauthorized: "no sé quién eres" — falta o es inválido el token.403 Forbidden: "sé quién eres pero no te dejo" — autenticado, sin permiso.
📚Material complementario▾
Pon a prueba tu intuición
Lee cada escenario y elige el código de estado correcto.
Asigna a cada escenario el código HTTP que devolverías como API.
Creaste un usuario nuevo y todo salió bien.
Pediste /api/usuarios/9999 pero no existe.
Enviaste un POST sin token de autenticación.
El servidor explotó por un bug en el código.
Borraste un recurso y no hay nada que devolver.
/ 5 aciertos
Cómo organizar el backend: tres caminos
No hay arquitectura "mejor": hay arquitectura adecuada al tamaño del problema.
Monolito
Todo el backend en una sola aplicación que se despliega como un bloque.
Ventajas: simple de desarrollar, desplegar y debuggear. Ideal al empezar.
Cuidado: conforme crece, se convierte en un "big ball of mud" si no hay disciplina.
Microservicios
Cada funcionalidad es un servicio independiente que se comunica por la red.
Ventajas: equipos autónomos, escala por servicio, fallos aislados.
Cuidado: complejidad operacional enorme — observabilidad, despliegue, latencias de red, datos distribuidos.
Serverless
Funciones que ejecuta el cloud bajo demanda: AWS Lambda, Vercel, Cloudflare Workers.
Ventajas: sin servidores que gestionar, escala automático, pagas por ejecución.
Cuidado: cold starts, límites de tiempo, vendor lock-in.
Empieza simple, complica solo cuando duela
Sí: empieza con monolito
- • Eres una persona o un equipo pequeño
- • No conoces todavía bien el dominio
- • Quieres iterar y descartar ideas rápido
- • Tu app aún no tiene picos de tráfico monstruosos
Considera microservicios cuando…
- • Múltiples equipos pisándose el código
- • Una parte tiene escala muy distinta del resto
- • Distintos lenguajes / runtimes por área
- • Tienes plataforma para soportarlo (k8s, observability)
Antipatrón clásico
Empezar un proyecto con 12 microservicios "porque es lo moderno". Casi siempre acabas con unmonolito distribuido: la complejidad de microservicios sin los beneficios.
📚Material complementario▾
Node.js — JavaScript fuera del navegador
En 2009 Ryan Dahl tomó el motor V8 de Chrome y lo empaquetó como un runtime de servidor. El resultado: el mismo lenguaje en frontend y backend.
Qué te da Node
- • Un runtime JS rápido (V8) en el servidor
- • APIs para ficheros, red, procesos, streams
- •
npm, el registro de paquetes más grande del mundo - • Modelo asíncrono no bloqueante (event loop)
El event loop en una frase
Node no abre un hilo por petición: usa un único hilo que delega la I/O al sistema operativo y atiende lo siguiente que esté listo. Por eso aguanta miles de conexiones simultáneas con poca memoria.
Alternativas modernas
Deno yBun son runtimes JS más recientes con TypeScript de fábrica y mejoras de rendimiento. La industria todavía corre casi todo en Node, pero merece la pena conocerlos.
Configurar un proyecto desde cero
Cuatro comandos y ya tienes un servidor Express listo para escribir endpoints.
mkdir mi-api && cd mi-apinpm init -ynpm install expressnpm install -D nodemon# añade en package.json:# "scripts": { "dev": "nodemon server.js" }npm run devpackage.json
Manifiesto del proyecto: nombre, versión, dependencias y scripts. Nunca lo edites a mano para añadir paquetes — usa npm install.
node_modules/
Carpeta con todas las dependencias instaladas. Pesa mucho:.gitignore siempre.
nodemon
Reinicia el servidor automáticamente cuando guardas un archivo. Sólo para desarrollo (de ahí -D).
📚Material complementario▾
Express — el framework web minimalista
Express te da un router HTTP, middleware y poco más. Su sencillez es justo lo que lo hizo el framework más usado del ecosistema Node.
// server.jsconst express = require('express');const app = express();const PORT = 3000;app.use(express.json());app.get('/', (req, res) => { res.json({ mensaje: 'Hola Backend' });});app.listen(PORT, () => { console.log(`http://localhost:${PORT}`);});app
Instancia de Express. Encadenas .use(), .get(),.post()... y al final .listen().
req, res
La petición y la respuesta. req.params,req.query, req.body, req.headers. En res usas res.json(), res.status(),res.send().
express.json()
Middleware integrado que parsea bodies JSON entrantes y los deja enreq.body. Sin esto, req.body es undefined.
Rutas, parámetros y respuestas
Tres formas de entrar datos al endpoint y cómo responder con el código adecuado.
// Path param: /api/usuarios/42app.get('/api/usuarios/:id', (req, res) => { const id = parseInt(req.params.id); const u = usuarios.find(u => u.id === id); if (!u) return res.status(404).json({ error: 'No existe' }); res.json(u);});// Query params: /api/buscar?q=laptop&limit=10app.get('/api/buscar', (req, res) => { const { q, limit = 20 } = req.query; res.json(buscar(q, +limit));});// Body: POST /api/usuariosapp.post('/api/usuarios', (req, res) => { const { nombre, email } = req.body; if (!nombre) return res.status(400).json({ error: 'nombre requerido' }); const nuevo = crear(nombre, email); res.status(201).json(nuevo);});Una API CRUD completa, en 30 líneas
Lista, lee, crea, actualiza y borra tareas. Sin base de datos: por ahora vivimos en un array en memoria.
let tareas = [{ id: 1, titulo: 'Aprender Express', hecha: false }];let next = 2;// LISTapp.get('/api/tareas', (_, res) => res.json(tareas));// READapp.get('/api/tareas/:id', (req, res) => { const t = tareas.find(t => t.id === +req.params.id); if (!t) return res.status(404).json({ error: 'No existe' }); res.json(t);});// CREATEapp.post('/api/tareas', (req, res) => { const { titulo } = req.body; if (!titulo) return res.status(400).json({ error: 'titulo requerido' }); const t = { id: next++, titulo, hecha: false }; tareas.push(t); res.status(201).json(t);});// UPDATE parcialapp.patch('/api/tareas/:id', (req, res) => { const t = tareas.find(t => t.id === +req.params.id); if (!t) return res.status(404).json({ error: 'No existe' }); Object.assign(t, req.body); res.json(t);});// DELETEapp.delete('/api/tareas/:id', (req, res) => { tareas = tareas.filter(t => t.id !== +req.params.id); res.status(204).send();});📚Material complementario▾
Middleware — el corazón de Express
Una función con firma (req, res, next) que se ejecuta entre la petición y la respuesta. Cada middleware puede leer, modificar, responder o pasar el control con next().
- 1
Petición entra
POST /api/tareas con { titulo: "Comprar pan" }
- 2
Middleware: logger
Imprime fecha, método y URL en consola.
- 3
Middleware: express.json()
Parsea el body JSON y lo deja en req.body.
- 4
Middleware: auth
Valida cabecera x-api-key. Si falta → 401.
- 5
Middleware: validador
Comprueba que titulo no esté vacío. Si lo está → 400.
- 6
Handler de ruta
Crea la tarea y devuelve 201 con el JSON.
- 7
Respuesta sale
HTTP/1.1 201 Created — JSON al cliente.
Cada middleware llama a next() para pasar el control al siguiente. Si alguno responde, la cadena se detiene.
Patrones que verás en cualquier API
Logger, validador, autenticación, rate limiter, manejador global de errores.
// 1) Logger globalapp.use((req, res, next) => { console.log(`${new Date().toISOString()} ${req.method} ${req.url}`); next();});// 2) Auth: solo deja pasar si hay API keyconst apiKey = (req, res, next) => { if (req.headers['x-api-key'] !== process.env.API_KEY) { return res.status(401).json({ error: 'Token inválido' }); } next();};// 3) Validación específicaconst validarTarea = (req, res, next) => { if (!req.body.titulo?.trim()) { return res.status(400).json({ error: 'titulo requerido' }); } next();};// 4) Encadenar varios en una rutaapp.post('/api/tareas', apiKey, validarTarea, handler);// 5) Manejador global de errores (4 args)app.use((err, req, res, next) => { console.error(err); res.status(500).json({ error: 'Error interno' });});📚Material complementario▾
CORS — el muro entre dominios
Por seguridad, el navegador bloquea peticiones desde un origen (localhost:5173) hacia otro (api.tienda.com) salvo que el servidor lo permita explícitamente. Eso es CORS.
// Activar CORS en Expressconst cors = require('cors');// Permite cualquier origen (sólo dev)app.use(cors());// Configuración granular en producciónapp.use(cors({ origin: ['https://midominio.com'], methods: ['GET', 'POST', 'PATCH', 'DELETE'], credentials: true,}));Síntomas típicos
En la consola del navegador:"Access to fetch at ... has been blocked by CORS policy". La petición sí sale, pero el navegador bloquea la respuesta.
Preflight
Para verbos no triviales, el navegador envía primero unOPTIONS. Si la respuesta no autoriza el origen y el método, el real ni siquiera se manda.
No es seguridad
CORS protege al usuario en el navegador. curl, Postman o tu propio backend pueden seguir llamando: la API necesita autenticación de verdad.
Probar tu API sin frontend
Antes de conectar el frontend conviene comprobar manualmente que la API responde como esperas. Tres herramientas indispensables.
curl
Línea de comandos. Disponible en cualquier sistema. Ideal para scripts y documentación reproducible.
curl -X POST \ -H 'Content-Type: application/json' \ -d '{"titulo":"Comprar pan"}' \http://localhost:3000/api/tareasPostman / Insomnia
GUI completa: colecciones de peticiones, entornos por servidor, variables, scripts y compartir con el equipo. El estándar de facto.
Bonus: pueden generar código (curl, fetch, axios...) con un clic.
Thunder Client / REST Client
Extensiones de VS Code. Sin salir del editor escribes la petición en un.http y la lanzas con F1.
POST http://localhost:3000/api/tareasContent-Type: application/json{ "titulo": "Test" }📚Material complementario▾
Resumen de la Clase 6
| Concepto | Definición |
|---|---|
| Backend | Parte del servidor que procesa lógica, datos y seguridad |
| HTTP | Protocolo stateless de petición/respuesta sobre el que corre la web |
| API | Contrato que define cómo dos sistemas se comunican |
| REST | Estilo arquitectónico basado en recursos, URLs y verbos HTTP |
| Endpoint | Combinación de verbo + URL que expone una operación |
| Verbos HTTP | GET, POST, PUT, PATCH, DELETE — la acción sobre el recurso |
| Códigos de estado | 2xx éxito, 4xx error de cliente, 5xx error de servidor |
| JSON | Formato textual ligero para intercambiar datos estructurados |
| Monolito | Backend como una sola aplicación; punto de partida razonable |
| Microservicios | Servicios independientes que se comunican por la red |
| Serverless | Funciones que ejecuta el cloud bajo demanda (Lambda, Vercel...) |
| Node.js | Runtime de JavaScript en el servidor con event loop no bloqueante |
| npm | Gestor de paquetes del ecosistema Node y registro público |
| Express | Framework web minimalista para Node.js |
| Middleware | Función (req, res, next) que se ejecuta en la cadena de la petición |
| CORS | Política del navegador que regula peticiones cross-origin |
📚Material complementario▾
Ejercicio 6.1: Diseñar una API REST
Sin escribir código, diseña los endpoints de una biblioteca digital. Debe gestionar libros, usuarios, préstamos y devoluciones.
| Verbo | Ruta | Descripción | Éxito |
|---|---|---|---|
| GET | /api/libros | Listar todos los libros | 200 |
| GET | /api/libros/:id | Obtener un libro | 200 |
| POST | /api/libros | Crear un libro | 201 |
| PUT | /api/libros/:id | Reemplazar un libro | 200 |
| DELETE | /api/libros/:id | Eliminar un libro | 204 |
| POST | /api/usuarios/:id/prestamos | Pedir prestado un libro | 201 |
| DELETE | /api/usuarios/:id/prestamos/:libroId | Devolver un libro | 204 |
| GET | /api/usuarios/:id/prestamos | Préstamos activos del usuario | 200 |
Fíjate en el patrón /usuarios/:id/prestamos: el préstamo es unsub-recurso que vive bajo un usuario.
Ejercicio 6.2: Tu primer servidor Express
Cuatro rutas que cubren path params, query params y body.
Rutas pedidas
- •
GET /→{ mensaje: 'Servidor funcionando' } - •
GET /api/saludo/:nombre→{ saludo: 'Hola, [nombre]!' } - •
GET /api/suma?a=5&b=3→{ resultado: 8 } - •
POST /api/eco→ devuelve el body recibido
const express = require('express');const app = express();app.use(express.json());app.get('/', (_, res) => res.json({ mensaje: 'Servidor funcionando' }));app.get('/api/saludo/:nombre', (req, res) => res.json({ saludo: `Hola, ${req.params.nombre}!` }));app.get('/api/suma', (req, res) => { const a = parseFloat(req.query.a) || 0; const b = parseFloat(req.query.b) || 0; res.json({ resultado: a + b });});app.post('/api/eco', (req, res) => res.json(req.body));app.listen(3000);Ejercicio 6.3: API CRUD de notas
Implementa la API y prueba en este simulador. Validación de título (mín. 3), contenido requerido, búsqueda por texto y filtro por categoría.
POST /api/notas
GET /api/notas
No hay notas que coincidan.
Ejercicio 6.4: Middleware personalizado
Añade tres middlewares a tu API: logger con tiempo, autenticación por API key y rate limiter por IP.
Logger
Imprime cada petición en consola con formato:
[2026-04-29 14:30:00] GET /api/notas - 200 (15ms)Pista: registra el inicio en req.startTime y al terminar usa el evento res.on('finish').
API key
Header x-api-key obligatorio. Si falta o no coincide con la variable de entorno API_KEY →401 Unauthorized.
Rate limiter
Máximo 10 peticiones por minuto por IP. Si se excede →429 Too Many Requests.
Pista: un Map en memoria con req.ip como clave.
Proyecto: API REST de Lista de Tareas
Construye una API REST completa para una aplicación de tareas concategorías y prioridades. Lista para ser consumida por cualquier frontend.
Modelo de datos
- •
id— entero autoincremental - •
titulo— string requerido - •
descripcion— string opcional - •
completada— boolean - •
prioridad— alta / media / baja - •
categoria— string libre - •
fechaCreacion— ISO automático
Funcionalidades
- • CRUD completo de tareas
- • Filtrado por estado, prioridad y categoría
- • Ordenamiento por fecha o prioridad
- •
GET /api/tareas/statscon totales - • Middleware de logging
- • Manejo de errores consistente
- • Códigos HTTP correctos en cada caso
Estructura sugerida
Separa cada responsabilidad en su archivo. No es obligatorio, pero te ahorra dolores cuando la API crezca.
mi-tareas-api/├── package.json├── server.js├── routes/│ └── tareas.js├── middleware/│ ├── logger.js│ └── errorHandler.js├── data/│ └── tareas.js└── README.mdserver.js
Punto de entrada. Configura middleware globales, monta los routers y arranca app.listen().
routes/
Un express.Router() por recurso. Cada archivo registra las rutas de su recurso y exporta el router.
middleware/
Funciones reutilizables: logger, validadores, errorHandler. Importa y enchúfalas con app.use().
Criterios de evaluación
Checklist
- ☑ CRUD completo funcional
- ☑ Códigos HTTP correctos (200, 201, 204, 400, 404...)
- ☑ Validación de datos de entrada
- ☑ Filtrado por estado, prioridad y categoría
- ☑ Ordenamiento por fecha o prioridad
- ☑ Endpoint
/statscon totales - ☑ Al menos un middleware personalizado
- ☑ Manejo de errores: nunca crashea el servidor
Bonus
- ⭐ Persistir en un archivo JSON entre reinicios
- ⭐ Variables de entorno con
dotenv - ⭐ Documentación con Swagger / OpenAPI
- ⭐ Colección Postman o archivo
.httpincluidos - ⭐ CORS configurado para tu portafolio
- ⭐ Despliegue en Render, Railway o Fly.io
- ⭐ Tests con Jest o Vitest + Supertest
Ya hablas el idioma del backend
HTTP, REST y Express son la base sobre la que se construyen las APIs modernas. En la próxima clase añadimos la pieza que faltaba:bases de datos, autenticación real con JWT y despliegue en producción.