Versionado de APIs

Estrategias para versionar APIs REST y GraphQL — versionado por URL, headers, semántico, compatibilidad hacia atrás y deprecación.

¿Por qué versionar APIs?

Cuando múltiples consumidores dependen de una API, cualquier cambio en su contrato puede romper integraciones existentes. El versionado permite evolucionar la API de forma controlada, dando tiempo a los consumidores para adaptarse.

Sin una estrategia de versionado clara, los equipos terminan en una de dos situaciones: o no pueden cambiar nada por miedo a romper consumidores, o rompen cosas constantemente sin darse cuenta.

Estrategias de versionado

Versionado por URL

La estrategia más común y visible. La versión se incluye directamente en la ruta:

GET /api/v1/products
GET /api/v2/products

Ventajas:

  • Extremadamente explícito — no hay ambigüedad sobre qué versión se está usando
  • Fácil de rutear en API Gateways y load balancers
  • Simple de documentar y comunicar

Desventajas:

  • Puede llevar a duplicación de código si no se estructura bien internamente
  • Los consumidores deben actualizar URLs al migrar

Versionado por headers

La versión se especifica en un header HTTP personalizado o en el header Accept:

GET /api/products
Accept: application/vnd.myapi.v2+json

O con un header custom:

GET /api/products
X-API-Version: 2

Ventajas:

  • Las URLs se mantienen limpias y estables
  • Permite negociación de contenido más sofisticada

Desventajas:

  • Menos visible — requiere inspeccionar headers para saber qué versión se usa
  • Más difícil de probar desde un navegador

Versionado semántico (SemVer)

Aplica los principios de Semantic Versioning a la API:

  • MAJOR (v1 → v2): Cambios breaking — incompatibles con versiones anteriores
  • MINOR (v1.1 → v1.2): Nuevas funcionalidades compatibles hacia atrás
  • PATCH (v1.1.0 → v1.1.1): Correcciones de bugs sin cambios funcionales

En la práctica, las APIs públicas suelen exponer solo la versión MAJOR en la URL (/v1/, /v2/) y manejar MINOR/PATCH internamente.

Compatibilidad hacia atrás

Un cambio es backward compatible si los consumidores existentes pueden seguir funcionando sin modificaciones. Ejemplos de cambios compatibles:

  • Agregar un campo nuevo opcional a una respuesta
  • Agregar un nuevo endpoint
  • Agregar un parámetro de query opcional
  • Agregar un nuevo valor a un enum (con cuidado)

Ejemplos de cambios breaking:

  • Eliminar un campo de la respuesta
  • Renombrar un campo existente
  • Cambiar el tipo de un campo (string → number)
  • Hacer obligatorio un campo que era opcional
  • Cambiar la semántica de un campo existente

Estrategias de deprecación

Cuando necesitás retirar una versión antigua:

1. Comunicación anticipada

Anunciá la deprecación con suficiente anticipación (mínimo 3-6 meses para APIs públicas):

Deprecation: true
Sunset: Sat, 01 Mar 2025 00:00:00 GMT
Link: <https://docs.api.com/migration/v2>; rel="successor-version"

2. Período de coexistencia

Mantené ambas versiones funcionando en paralelo durante el período de transición. Monitoreá el tráfico de la versión antigua para saber cuándo es seguro retirarla.

3. Respuestas con warnings

Incluí headers de advertencia en las respuestas de la versión deprecada:

Warning: 299 - "API v1 is deprecated. Please migrate to v2 by 2025-03-01"

4. Sunset definitivo

Una vez pasada la fecha de sunset, las llamadas a la versión antigua pueden devolver 410 Gone con un cuerpo que explique cómo migrar.

Buenas prácticas

  • Versioná desde el día uno — es mucho más fácil empezar con /v1/ que agregar versionado después
  • Documentá los cambios — mantené un changelog claro por versión
  • Usá feature flags internamente — para manejar diferencias entre versiones sin duplicar código
  • Monitoreá el uso por versión — sabé cuántos consumidores usan cada versión antes de deprecar
  • Definí una política de soporte — cuántas versiones mantenés simultáneamente y por cuánto tiempo