Saltar a contenido

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

  1. 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).
  2. v1 es 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.json no lleva versión (no es API REST de negocio).
  3. 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).
  4. Cambios no rompedores (nuevo endpoint, campo opcional, enumerado nuevo) no suben la versión del path.
  5. Coexistencia y deprecación: al publicar v2, v1 se mantiene vivo un mínimo definido por el dueño (ej. 2 ciclos de release), con Deprecation en el OpenAPI y log de consumidores; luego se apaga. Nunca se borra vN sin aviso.
  6. OpenAPI es el contrato: cada servicio publica su openapi.json versionado; el major va en el path y también en info.version. Los contract tests en CI validan que v1 no cambia de forma rompedora entre releases (regla 5 del ADR 0003; mecanismo en el ADR 0017 transversal).
  7. Consumo:
  8. El frontend genera sus tipos desde el OpenAPI del path versionado (/api/v1/openapi.json) — ADR 0007 transversal.
  9. Los clientes de los servicios internos cachean el path versionado completo; un v2 es un cliente nuevo, no un cambio silencioso.
  10. 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 cantidadcantidad_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 v2 y convivir con v1, 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.