0016. Contratos y versionado de API¶
Fecha: 2026-09-08 Estado: Propuesto Módulo(s) afectado(s): todos los microservicios (backend y frontend) — transversal
Contexto¶
La regla 5 del ADR 0003 (plataforma microservicios) exige "contrato antes
que código: OpenAPI versionado + contract tests en CI", pero no define el
esquema concreto de versionado. Como resultado, los ADRs y ejemplos usan
paths sin versión (/api/pedidos, /api/usuarios/{id}) y el frontend y los
servicios no tienen una regla única de consumo.
Error típico: versionar solo en cabecera (Api-Version) o no versionar el
path. Cambiar un contrato después de público es caro; el path versionado es
lo más barato ahora ("reglas no negociables" del ADR 0003).
Decisión¶
Todo microservicio expone su API REST bajo /api/v<major>/.
https://<servicio>/api/v1/usuarios
https://<servicio>/api/v1/navegacion/panel
Reglas¶
- Versionado en el path:
/api/v1/...,/api/v2/...— nunca en query ni solo en cabecera. La versión es parte de la URL (explicita, cacheable, testeable con contract tests). v1es la versión inicial de todo servicio nuevo. El endpoint de autenticación también se versiona:/api/v1/auth/login, etc. El/.well-known/jwks.jsonno lleva versión (no es API REST de negocio).- Semver del contrato, no del artefacto: la versión del path sube únicamente con cambios rompedores (se quita/renombra una ruta o campo, cambia un tipo, se exige un campo nuevo obligatorio).
- Cambios no rompedores (nuevo endpoint, campo opcional, enumerado nuevo) no suben la versión del path.
- Coexistencia y deprecación: al publicar
v2,v1se mantiene vivo un mínimo definido por el dueño (ej. 2 ciclos de release), conDeprecationen el OpenAPI y log de consumidores; luego se apaga. Nunca se borravNsin aviso. - OpenAPI es el contrato: cada servicio publica su
openapi.jsonversionado; el major va en el path y también eninfo.version. Los contract tests en CI validan quev1no cambia de forma rompedora entre releases (regla 5 del ADR 0003; mecanismo en el ADR 0017 transversal). - Consumo:
- El frontend genera sus tipos desde el OpenAPI del path versionado
(
/api/v1/openapi.json) — ADR 0007 transversal. - Los clientes de los servicios internos cachean el path versionado
completo; un
v2es un cliente nuevo, no un cambio silencioso. - Dentro de un servicio en FastAPI, los routers se montan con el prefijo:
app.include_router(router, prefix="/api/v1")
Ejemplo¶
| Versión | Ruta | Estado |
|---|---|---|
| v1 | GET /api/v1/pedidos |
vigente |
v2 (rompe: renombra cantidad → cantidad_facturable) |
GET /api/v2/pedidos |
nuevo |
| v1 | GET /api/v1/usuarios/{id} |
vigente, deprecándose |
Alternativas descartadas¶
- Versionado en cabecera (
Api-Version) — invisible en URLs/logs, complica el cache y los contract tests. - Sin versionado ("v1 a la primera, cambia todo") — rompe consumidores sin aviso; el frontend y los servicios externos se quiebran a la vez.
- Versionado solo en el payload/recurso — no hay ruta clara de coexistencia para migraciones suaves.
Consecuencias¶
- Cambiar de contrato implica publicar
v2y convivir conv1, nunca editar en silencio. - Los ADRs de cada servicio escriben sus endpoints con el prefijo
/api/v1/desde el día uno. - El OpenAPI firmado y cacheado por el frontend hace que un major sea una migración explícita, verificable por los contract tests en CI.