Cerramos el módulo 1 diciendo que tocaba pasar de comprender a construir. Antes de escribir la primera línea de servidor, hay una etapa que se salta demasiada gente y que es exactamente donde se ganan o se pierden los proyectos de API: el diseño del contrato. Esta lección es la lección paraguas del módulo 2. No entra todavía en cómo se nombran las URIs ni en qué código de estado devolver —eso son las lecciones siguientes—, sino en el método de trabajo: cómo se decide qué API hay que construir, con qué principios rectores y con qué artefactos. Al final de la lección tendrás en la mano la guía de estilo de la API de Tienda Aroma, un documento vivo que las siete lecciones siguientes irán rellenando y que el módulo 3 implementará al pie de la letra.
Contenido
- API-first frente a code-first
- El proceso de diseño en siete pasos
- Paso 1: identificar consumidores y casos de uso
- Paso 2: extraer los sustantivos del dominio
- Paso 3: decidir qué se convierte en recurso y qué no
- Principios rectores del diseño
- Granularidad: ni demasiado fina ni demasiado gruesa
- Diseñar para el consumidor, no para la base de datos
- Tolerancia a la evolución y principio de robustez
- La guía de estilo de la API de Tienda Aroma
- Mapa del módulo 2
- API-first frente a code-first
Hay dos maneras de llegar a tener una API, y no dan el mismo resultado.
En el enfoque code-first se escribe primero la aplicación y la API aparece después, casi como un subproducto: se toman los servicios que ya existen, se les cuelga una capa HTTP y se genera la documentación a partir del código. Es rápido al principio y funciona razonablemente bien cuando el único consumidor es tu propio frontend.
En el enfoque API-first se hace lo contrario: el contrato se diseña, se revisa y se acuerda antes de implementar nada. La especificación es el artefacto principal; el código es su realización. Los consumidores pueden empezar a trabajar contra un simulacro (mock) generado desde el contrato mientras el equipo de servidor lo implementa.
| Criterio | Code-first | API-first |
|---|---|---|
| Punto de partida | El código existente | El contrato acordado |
| Quién decide la forma de la API | La implementación y el ORM | Los consumidores y el dominio |
| Cuándo pueden empezar los clientes | Cuando hay servidor funcionando | El primer día, contra un mock |
| Coste de un cambio de diseño | Alto: hay código escrito | Bajo: se edita un documento |
| Riesgo de filtrar detalles internos | Alto | Bajo |
| Documentación | Generada al final, a remolque | Es la fuente, siempre al día |
| Bueno para | Prototipos, API interna de un solo cliente | APIs con varios consumidores o externas |
Tienda Aroma tiene cuatro consumidores distintos y uno de ellos es una empresa externa. Rediseñar el contrato después de que RápidoEnvíos haya integrado sus sistemas cuesta reuniones, versiones y dinero. Por eso el curso adopta API-first: el módulo 2 completo diseña el contrato sobre el papel y el módulo 3 lo implementa.
Un matiz honesto: API-first no significa "diseñarlo todo perfecto antes de tocar código". Significa que el contrato va por delante y se revisa como se revisa el código. Se puede iterar, pero se itera sobre el documento, no sobre una API ya publicada.
- El proceso de diseño en siete pasos
graph TD
A["1. Identificar consumidores<br/>y casos de uso"] --> B["2. Extraer sustantivos<br/>del dominio"]
B --> C["3. Decidir qué es recurso<br/>y qué no"]
C --> D["4. Nombrar URIs y<br/>definir jerarquías"]
D --> E["5. Asignar métodos,<br/>códigos y representaciones"]
E --> F["6. Escribir el contrato<br/>(OpenAPI) y revisarlo"]
F --> G["7. Publicar mocks y<br/>validar con consumidores"]
G -.->|"hallazgos"| A
Los pasos 1 a 3 son esta lección. Los pasos 4 y 5 son las lecciones 02-02 a 02-06. El paso 6 aterriza en 02-07 y 02-08. El paso 7 se trabaja a fondo en 05-04. El ciclo se cierra: lo que aprendes validando con consumidores vuelve al principio.
- Paso 1: identificar consumidores y casos de uso
Una API no se diseña "para el dominio": se diseña para alguien que la va a llamar. El primer entregable no es una lista de endpoints, sino una lista de consumidores con sus necesidades reales.
| Consumidor | Quién es | Qué necesita | Restricciones |
|---|---|---|---|
| SPA de la tienda web | Aplicación en el navegador | Catálogo, ficha de café, carrito, checkout | Navegador: CORS, latencia visible, sin secretos |
| Aroma Móvil | App nativa iOS/Android | Lo mismo, en pantallas pequeñas | Red móvil variable, versiones antiguas conviviendo meses |
| Panel interno | Herramienta de back-office | Gestión de stock, moderación de reseñas, pedidos | Volúmenes grandes, listados con filtros, tiempo real |
| RápidoEnvíos | Socio de mensajería | Recibir pedidos pagados, informar de envíos | Externo: contrato estable, reintentos, firma HMAC |
De ahí salen los casos de uso, escritos como frases de usuario, no como endpoints:
- "Como visitante quiero ver los cafés disponibles filtrados por origen y tueste."
- "Como cliente quiero añadir dos bolsas de Etiopía Yirgacheffe a mi carrito y pagarlo."
- "Como cliente quiero consultar el estado de mi pedido y descargar la factura."
- "Como moderador quiero aprobar o rechazar una reseña pendiente."
- "Como RápidoEnvíos quiero enterarme de que un pedido se ha pagado sin tener que preguntar cada minuto."
Este último caso de uso es el que hizo aparecer los webhooks en 01-07: la lista de casos de uso también decide la arquitectura, no solo los endpoints.
Un detalle importante: los consumidores tienen necesidades distintas y a veces enfrentadas. Aroma Móvil quiere respuestas pequeñas porque paga la red; el panel interno quiere respuestas ricas porque pinta tablas con muchas columnas. Esa tensión no se resuelve creando dos APIs paralelas, sino con mecanismos de contrato: selección de campos y expansión, que se diseñan en 02-05.
- Paso 2: extraer los sustantivos del dominio
La técnica es deliberadamente simple: escribe en prosa lo que hace el negocio y subraya los sustantivos.
"Un cliente navega por el catálogo de cafés, cada uno con su origen, su tueste y sus notas de cata. Añade líneas a su carrito y confirma un pedido, que tiene un total y un estado. El pedido se paga y genera una factura. Cuando se paga, RápidoEnvíos crea un envío. Después, el cliente puede escribir una reseña de un café, que un moderador aprueba o rechaza, y a la que la tienda puede publicar una respuesta."
Sustantivos candidatos: cliente, catálogo, café, origen, tueste, notas de cata, línea, carrito, pedido, total, estado, pago, factura, envío, reseña, respuesta, moderador.
Y los verbos, que anotamos aparte porque son la fuente de los problemas más interesantes: navegar, añadir, confirmar, pagar, generar, aprobar, rechazar, responder.
- Paso 3: decidir qué se convierte en recurso y qué no
No todos los sustantivos merecen una URI. Aplica estos filtros:
- ¿Tiene identidad propia? ¿Puedes señalarlo y decir "este de aquí"? Un pedido sí (
ped_5001); un total, no: es un atributo de un pedido. - ¿Alguien necesita direccionarlo por separado? Una reseña sí: se modera de una en una. Un tueste no: es un valor de un enumerado.
- ¿Tiene ciclo de vida propio? Un envío nace, cambia de estado y termina. Una nota de cata no: vive y muere con su café.
- ¿Se manipula independientemente de su padre? Una línea de carrito sí, porque se cambia la cantidad sin tocar el resto.
Aplicado a Tienda Aroma:
| Sustantivo | ¿Recurso? | Decisión |
|---|---|---|
| Café | Sí | Colección /cafes |
| Cliente | Sí | Colección /clientes |
| Pedido | Sí | Colección /pedidos |
| Reseña | Sí | Colección /resenas, también anidada bajo su café |
| Carrito | Sí | Colección /carritos |
| Línea de carrito | Sí, subrecurso | /carritos/{id}/lineas/{cafeId} |
| Pago | Sí, subrecurso | /pedidos/{id}/pago |
| Factura | Sí, subrecurso | /pedidos/{id}/factura |
| Envío | Sí, subrecurso | /pedidos/{id}/envio |
| Catálogo | No | Es la colección /cafes, no un recurso aparte |
| Origen, tueste, notas de cata | No | Atributos de un café |
| Total, estado | No | Atributos de un pedido |
| Moderador | No en v1 | Es un rol de usuario, no un recurso público |
La columna de la derecha se justifica en 02-02, que es donde se explican las reglas de nombrado, el anidamiento y los singleton. Aquí lo importante es el criterio: recurso es aquello que tiene identidad, ciclo de vida y necesidad de ser direccionado.
- Principios rectores del diseño
Estos seis principios son los que aplicaremos, lección tras lección, cada vez que haya que decidir algo.
6.1. Consistencia por encima de la elegancia puntual
Si /cafes acepta ?limite=20, entonces /pedidos acepta ?limite=20, aunque para pedidos hubieras preferido llamarlo ?tamano. Una API con veinte decisiones buenas pero distintas entre sí es peor que una API con veinte decisiones aceptables e idénticas: el consumidor aprende la primera y deduce las diecinueve restantes.
6.2. Previsibilidad ("adivinabilidad")
Un desarrollador que ya ha usado GET /v1/cafes/caf_001 debería poder escribir GET /v1/pedidos/ped_5001 sin abrir la documentación y acertar. Prueba práctica: enseña tres endpoints a alguien y pídele que escriba el cuarto. Si acierta, la API es previsible.
# Si esto funciona así...
curl https://api.tiendaaroma.example/v1/cafes/caf_001
curl "https://api.tiendaaroma.example/v1/cafes?tueste=medio&limite=10"
# ...esto debería funcionar igual, sin consultar la documentación
curl https://api.tiendaaroma.example/v1/pedidos/ped_5001
curl "https://api.tiendaaroma.example/v1/pedidos?estado=pagado&limite=10"6.3. Orientación a recursos y no a acciones
La API expone cosas sobre las que se opera con los métodos de HTTP, no funciones remotas. POST /v1/pedidos/ped_5001/pago en lugar de POST /v1/pagarPedido. Esto ya lo justificamos en 01-04 y 01-05; el caso difícil —las acciones que no encajan en CRUD— se resuelve en 02-02.
6.4. Simetría entre operaciones
Si el GET de un café devuelve precioEuros y stock, el POST que lo crea debería aceptar esos mismos nombres de campo. Si POST /cafes devuelve el recurso creado, PUT /cafes/{id} también debería devolver el recurso actualizado. Las asimetrías gratuitas obligan a memorizar excepciones.
6.5. Contrato explícito y estable
Todo lo que el consumidor puede observar forma parte del contrato: nombres de campo, tipos, códigos de estado, cabeceras, mensajes de error, orden por defecto de una colección. Lo que no quieras garantizar, no lo expongas. Y lo que expongas, no lo cambies sin versionar (02-07).
6.6. Errores que enseñan
Un error es una respuesta más y se diseña igual de bien que un éxito. Debe decir qué ha fallado, por qué y qué puede hacer el cliente. El formato lo fija 02-04.
- Granularidad: ni demasiado fina ni demasiado gruesa
La granularidad es cuánto trabajo hace una sola llamada. Es una de las decisiones con más consecuencias y no tiene respuesta universal.
API demasiado fina. Cada recurso mínimo tiene su endpoint y el cliente compone. Pintar la ficha de un café obliga a: pedir el café, pedir sus reseñas, pedir el cliente de cada reseña... Es la chattiness (verborrea): muchas idas y vueltas. En una red móvil con 150 ms de latencia, ocho llamadas encadenadas son más de un segundo perdido solo en viajes.
API demasiado gruesa. Un único endpoint devuelve el café con sus reseñas, los clientes de las reseñas, el stock por almacén y las recomendaciones. Una sola llamada, pero: respuestas enormes, casi todo sin usar (over-fetching), caché inútil (cualquier cambio invalida todo) y un contrato acoplado a una pantalla concreta que se romperá cuando la pantalla cambie.
| Síntoma | Diagnóstico | Remedio de diseño |
|---|---|---|
| El cliente hace 5+ llamadas para una pantalla | Demasiado fina | Expansión opcional (expandir=), subrecursos con datos incrustados |
| Se descargan campos que nadie usa | Demasiado gruesa | Selección de campos (campos=), enlaces en vez de incrustar |
| Un endpoint solo lo usa una pantalla | Acoplada a la interfaz | Rediseñar en torno al recurso, no a la vista |
| Cambiar una pantalla obliga a tocar la API | Acoplada a la interfaz | Volver a la orientación a recursos |
La postura de Tienda Aroma: una API de granularidad media orientada a recursos, con dos válvulas de escape controladas que se diseñan en 02-05 —expansión (expandir) para reducir llamadas y selección de campos (campos) para reducir peso— y datos ya incrustados donde el uso real lo pide (el nombre del café dentro de una línea de pedido, para que el cliente no tenga que resolver cada cafeId).
- Diseñar para el consumidor, no para la base de datos
El error más frecuente y más caro: publicar las tablas. Se toma el esquema relacional, se genera un endpoint por tabla y se llama a eso API REST.
Qué pasa cuando exponemos la tabla cafes tal cual:
{
"id_cafe": 1,
"nombre_cafe": "Etiopía Yirgacheffe",
"fk_origen": 12,
"cod_tueste": 1,
"precio_cent": 1450,
"stock_actual": 120,
"borrado_logico": 0,
"fec_alta": "2026-01-15 08:30:00",
"usuario_alta": "admin",
"version_fila": 7
}Problemas: el consumidor tiene que traducir cod_tueste: 1 a "claro" con una tabla que no tiene; fk_origen: 12 no le dice nada; precio_cent le obliga a conocer una decisión de almacenamiento; borrado_logico, usuario_alta y version_fila son fontanería interna que ahora forma parte del contrato y no se puede quitar sin romper clientes. Y si mañana se normaliza la tabla, la API se rompe.
La representación diseñada para el consumidor:
{
"id": "caf_001",
"nombre": "Etiopía Yirgacheffe",
"origen": "Etiopía",
"tueste": "claro",
"precioEuros": 14.50,
"stock": 120,
"notasCata": ["cítrico", "floral", "té negro"],
"fechaCreacion": "2026-01-15T08:30:00Z"
}La regla es: la representación es una proyección pensada para quien la lee, no un volcado de la fila. La base de datos puede seguir guardando céntimos, claves foráneas y banderas de borrado; eso es asunto de la capa de persistencia (03-05).
- Tolerancia a la evolución y principio de robustez
El principio de robustez de Jon Postel dice: "sé conservador en lo que envías, liberal en lo que aceptas". Traducido a una API:
- Como servidor: emite exactamente lo que promete el contrato. Nada de campos que aparecen a veces ni de tipos que cambian.
- Como cliente: no te rompas porque llegue un campo que no esperabas. Esto es el tolerant reader, y es lo que permite que el servidor añada campos sin publicar una versión nueva.
Consecuencias de diseño que adoptamos ya:
- Los enumerados pueden crecer. Si mañana aparece
tueste: "muy_oscuro", los clientes deben ignorarlo con elegancia, no reventar. Se documenta desde el día uno. - Los campos nuevos son opcionales y aditivos.
- Nunca se reutiliza un nombre de campo con otro significado.
- Las colecciones van envueltas en un objeto (
{"datos": [...], "total": n}) precisamente para poder añadir metadatos sin cambiar el tipo de la respuesta. Se argumenta en 02-05.
Qué es exactamente un cambio rompedor y qué no, y cómo se gestiona la deprecación, es la lección 02-07.
- La guía de estilo de la API de Tienda Aroma
Este es el artefacto central del módulo. Una guía de estilo es un documento corto, versionado en el repositorio, donde se escriben las convenciones que toda la API respeta. Sirve para tres cosas: decidir rápido, revisar en pull request y onboarding de gente nueva.
Empezamos con las decisiones ya tomadas (módulo 1) y las que este módulo irá cerrando:
| Ámbito | Convención de Tienda Aroma | Ejemplo | Se detalla en |
|---|---|---|---|
| Base URL | https://api.tiendaaroma.example/v1 |
— | 02-07 |
| Nombres de colección | Sustantivo en plural, minúsculas | /cafes, /pedidos |
02-02 |
| Palabras compuestas en URI | kebab-case | /notas-cata |
02-02 |
| Identificadores | Opacos, con prefijo de tipo | caf_001, ped_5001 |
02-02 |
| Acciones no CRUD | Subrecurso + POST | POST /pedidos/{id}/pago |
02-02 |
| Métodos | GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS | — | 02-03 |
| Actualización parcial | PATCH con JSON Merge Patch |
application/merge-patch+json |
02-03 |
| Reintentos seguros | Cabecera Idempotency-Key en POST sensibles |
pago de un pedido | 02-03 |
| Códigos de estado | Los estándar, sin inventar | 201 + Location al crear |
02-04 |
| Formato de error | {"error": {"codigo", "mensaje", "detalles"}} |
cafe_no_encontrado |
02-04 |
| Nombres en JSON | camelCase | precioEuros, fechaCreacion |
02-05 |
| Fechas y horas | ISO-8601 en UTC con Z |
2026-03-14T10:32:00Z |
02-05 |
| Importes | Número en euros con dos decimales, sufijo Euros |
14.50 |
02-05 |
| Enumerados | snake_case en minúsculas, ampliables |
pendiente_pago |
02-05 |
| Colecciones | Envoltorio {"datos": [...], "total": n} |
— | 02-05 |
| Enlaces | Nivel Richardson 2 con hipermedia selectiva | _links.self |
02-05 |
| Idioma del contenido | Accept-Language para notasCata |
es, ca, en |
02-05 |
| Paginación | limite + desplazamiento, más cabecera Link |
?limite=20 |
02-06 |
| Ordenación | ?ordenar=campo / ?ordenar=-campo |
?ordenar=-precioEuros |
02-06 |
| Búsqueda | ?q= sobre la colección |
?q=yirgacheffe |
02-06 |
| Versionado | En la ruta: /v1 |
— | 02-07 |
| Deprecación | Cabeceras Deprecation y Sunset |
— | 02-07 |
| Documentación | OpenAPI 3.1 en el repositorio | openapi.yaml |
02-08 |
| Idioma del código | Identificadores y comentarios en español | obtenerCafes |
Módulo 3 |
Dos advertencias sobre las guías de estilo:
- Se escriben para cumplirse. Una guía que nadie revisa en las pull requests es decorado. En 05-05 veremos cómo automatizar parte de la comprobación (linters de OpenAPI).
- Las convenciones son arbitrarias, la consistencia no.
camelCaseno es objetivamente mejor quesnake_case; lo que es objetivamente peor es usar los dos.
- Mapa del módulo 2
graph LR
L1["02-01<br/>Principios<br/><i>el método</i>"] --> L2["02-02<br/>Recursos y URIs<br/><i>el qué y el dónde</i>"]
L2 --> L3["02-03<br/>Métodos HTTP<br/><i>el cómo</i>"]
L3 --> L4["02-04<br/>Códigos de estado<br/><i>el resultado</i>"]
L4 --> L5["02-05<br/>Representaciones<br/><i>el cuerpo</i>"]
L5 --> L6["02-06<br/>Colecciones<br/><i>filtrar y paginar</i>"]
L6 --> L7["02-07<br/>Versionado<br/><i>el tiempo</i>"]
L7 --> L8["02-08<br/>Documentación<br/><i>el contrato publicado</i>"]
Al terminar el módulo tendrás el contrato completo de la API de Tienda Aroma: sus URIs, sus métodos, sus códigos, sus representaciones, sus colecciones paginadas, su política de versiones y su documentación. El módulo 3 lo implementa con Node.js y Express sin inventarse nada nuevo.
Errores Comunes y Consejos
- Empezar por los endpoints. Si tu primera hoja de diseño es una lista de URLs, te has saltado a los consumidores y al dominio. Empieza por casos de uso escritos en lenguaje de negocio.
- Diseñar la API mirando el ORM. Los nombres de columna, las claves foráneas y las banderas internas no son contrato. Proyecta, no vuelques.
- Diseñar la API mirando la pantalla. El extremo opuesto y también dañino: endpoints que solo sirven para una vista concreta envejecen con esa vista. Diseña recursos y da al cliente herramientas (
campos,expandir) para adaptarlos. - Optimizar antes de tener el problema. No añadas expansión, filtros exóticos ni caché de negocio "por si acaso". Cada mecanismo del contrato hay que documentarlo, probarlo y mantenerlo para siempre.
- Confundir consistencia con rigidez. Habrá excepciones legítimas (la factura en PDF, por ejemplo). Lo importante es que sean pocas, conscientes y escritas en la guía de estilo, no accidentes.
- Consejo: escribe primero la respuesta. Antes de decidir la URL, escribe a mano el JSON que querrías recibir en el caso de uso principal. Muchas decisiones de diseño se aclaran solas al verlo.
- Consejo: la prueba del desarrollador nuevo. Si alguien que no ha participado en el diseño necesita preguntar cómo se llama el parámetro de paginación, la API no es previsible todavía.
Ejercicios
Ejercicio 1: separar recursos de atributos
Tienda Aroma quiere añadir suscripciones: un cliente recibe una bolsa de café cada mes, con una periodicidad, un método de pago, una dirección de entrega y un historial de entregas ya realizadas. Además, cada suscripción puede pausarse.
Decide, justificándolo con los cuatro criterios de la sección 5, cuáles de estos sustantivos son recursos y cuáles atributos: suscripción, periodicidad, método de pago, dirección de entrega, entrega, pausa.
Ejercicio 2: diagnosticar la granularidad
La pantalla de "mis pedidos" de Aroma Móvil hace hoy estas llamadas:
GET /v1/clientes/cli_842/pedidos # 12 pedidos
GET /v1/pedidos/ped_5001 # una por pedido, 12 llamadas
GET /v1/cafes/caf_001 # una por línea, ~25 llamadasY la pantalla solo muestra, por pedido: fecha, estado, total y el nombre del primer café. Diagnostica el problema y propón dos soluciones de diseño distintas, indicando el inconveniente de cada una.
Ejercicio 3: ampliar la guía de estilo
Añade a la tabla de la sección 10 tres filas nuevas que hoy no están y que sabes que harán falta, para estos tres asuntos: (a) cómo se llaman las cabeceras propias de Tienda Aroma, (b) qué zona horaria se usa en las fechas de entrada que envía el cliente, (c) qué pasa con los campos desconocidos que un cliente envíe en el cuerpo de un POST. Redacta la convención en una frase por fila.
Soluciones
Solución 1
| Sustantivo | ¿Recurso? | Justificación |
|---|---|---|
| Suscripción | Sí | Identidad propia (sus_310), ciclo de vida (activa → pausada → cancelada), se direcciona sola. Colección /suscripciones. |
| Periodicidad | No | Atributo de la suscripción (periodicidad: "mensual"). No tiene identidad ni ciclo de vida. |
| Método de pago | Sí, pero no como subrecurso de suscripción | Tiene identidad y se reutiliza entre pedidos y suscripciones: colección propia /metodos-pago, referenciada por id desde la suscripción. |
| Dirección de entrega | Depende | Si el cliente guarda varias, es recurso (/clientes/{id}/direcciones). Si solo hay una por suscripción, es un objeto anidado en su representación. Decide según el caso de uso, no según la tabla. |
| Entrega | Sí, subrecurso | Cada entrega tiene fecha, estado y seguimiento: /suscripciones/{id}/entregas. No tiene sentido fuera de su suscripción. |
| Pausa | Sí, como acción modelada como subrecurso | No es un dato, es una transición: POST /suscripciones/{id}/pausa, coherente con /aprobacion y /anulacion. Se detalla en 02-02. |
Solución 2
Diagnóstico: API demasiado fina para este caso de uso. La pantalla necesita cuatro datos por pedido y provoca del orden de 38 llamadas. Es chattiness pura, agravada porque Aroma Móvil sufre latencia de red móvil. Además hay over-fetching en el otro sentido: de cada café se descarga todo para leer solo nombre.
Solución A — que la colección devuelva ya lo que se pinta. GET /v1/clientes/cli_842/pedidos devuelve cada pedido con fechaCreacion, estado, totalEuros y las líneas con el nombre del café ya incrustado. Una sola llamada.
Inconveniente: se duplica el nombre del café en muchas respuestas y hay que mantener esa copia coherente; además la respuesta crece para todos los consumidores, incluidos los que no necesitan las líneas.
Solución B — expansión y selección de campos. GET /v1/clientes/cli_842/pedidos?expandir=lineas.cafe&campos=id,fechaCreacion,estado,totalEuros,lineas. Una llamada, y cada consumidor pide lo que necesita.
Inconveniente: mecanismos que hay que documentar, validar y probar; abren la puerta a consultas caras y complican la caché, porque cada combinación de parámetros es una URL distinta.
(La decisión de Tienda Aroma combina las dos: incrusta el nombre del café en las líneas —dato estable y siempre necesario— y ofrece expandir/campos como válvula. Se cierra en 02-05.)
Solución 3
| Ámbito | Convención de Tienda Aroma | Ejemplo |
|---|---|---|
| Cabeceras propias | Prefijo Aroma- en PascalCase con guiones; nunca X- (obsoleto por RFC 6648) |
Aroma-Evento-Id, Aroma-Firma |
| Fechas de entrada | Se aceptan solo en ISO-8601 con zona horaria explícita; el servidor las normaliza y almacena en UTC | 2026-03-14T11:32:00+01:00 |
| Campos desconocidos en el cuerpo | Se rechazan con 400 y código datos_invalidos, indicando el campo en detalles, para detectar erratas pronto |
{"nombrre": "..."} → error |
Sobre la última: es una decisión discutible y conviene entenderla. Rechazar campos desconocidos (strict) detecta erratas del cliente al instante; ignorarlos (tolerant) facilita que un cliente nuevo hable con un servidor viejo. Tienda Aroma es estricta en la entrada y tolerante en la salida, que es exactamente el principio de robustez de la sección 9.
Conclusión
Diseñar una API RESTful no empieza por dibujar URLs: empieza por saber quién la va a usar y para qué, extraer los sustantivos del dominio y decidir con criterio cuáles merecen ser recursos. A partir de ahí, un puñado de principios rectores —consistencia, previsibilidad, orientación a recursos, simetría, contrato estable y errores útiles— resuelven la mayoría de las decisiones del día a día, mientras que la granularidad y el rechazo a exponer la base de datos evitan los dos errores estructurales más caros. Todo eso se materializa en un artefacto concreto: la guía de estilo, que hemos abierto con las decisiones ya firmes de Tienda Aroma y que iremos rellenando en cada lección.
Con el método claro y los consumidores identificados, toca la primera decisión concreta del contrato: qué recursos existen y cómo se llaman sus URIs. En la lección siguiente, 02-02 Recursos y URIs, convertiremos la lista de sustantivos en un mapa completo de direcciones —colecciones, elementos, subrecursos anidados y singleton—, fijaremos las reglas de nombrado, distinguiremos qué va en la ruta y qué en la query string, elegiremos el tipo de identificador y resolveremos el problema que ningún CRUD resuelve solo: cómo se modelan acciones como pagar un pedido o moderar una reseña.
Curso de REST API: Principios de Diseño y Desarrollo de APIs RESTful
Módulo 1: Introducción a las APIs RESTful
- ¿Qué es una API?
- Historia y evolución de las APIs
- Fundamentos de HTTP para APIs
- Principios básicos de REST
- Modelo de madurez de Richardson y HATEOAS
- REST vs. SOAP
- REST frente a GraphQL, gRPC y webhooks
Módulo 2: Diseño de APIs RESTful
- Principios de diseño de APIs RESTful
- Recursos y URIs
- Métodos HTTP
- Códigos de estado HTTP
- Representaciones, cabeceras y negociación de contenido
- Filtrado, ordenación, paginación y búsqueda
- Versionado de APIs
- Documentación de APIs
Módulo 3: Desarrollo de APIs RESTful
- Configuración del entorno de desarrollo
- Creación de un servidor básico
- Manejo de peticiones y respuestas
- Validación de datos de entrada
- Persistencia y capa de acceso a datos
- Autenticación y autorización
- Manejo de errores
- Pruebas y validación
Módulo 4: Buenas Prácticas y Seguridad
- Buenas prácticas en el diseño de APIs
- Seguridad en APIs RESTful
- OAuth 2.0 y OpenID Connect en la práctica
- Rate limiting y throttling
- CORS y políticas de seguridad
- Caché HTTP y rendimiento
- Observabilidad: logs, métricas y trazas
Módulo 5: Herramientas y Frameworks
- Postman para pruebas de APIs
- Swagger y OpenAPI para documentación
- Frameworks populares para APIs RESTful
- Contratos, mocks y pruebas automatizadas de API
- Integración continua y despliegue
- API gateways y portales de desarrollador
