Audiencia
Esta guía es para desarrolladores y arquitectos que necesitan evolucionar APIs sin romper clientes existentes:
- Desarrolladores backend manteniendo APIs que necesitan cambiar con el tiempo
- Arquitectos de API diseñando estrategias de versionado para nuevas APIs
- Tech leads estableciendo políticas de gobernanza de APIs para sus equipos
- Ingenieros DevOps gestionando despliegues y migraciones de APIs
- Product managers entendiendo el impacto de los cambios de API en las integraciones
Deberías entender ya los conceptos básicos de REST APIs. Si no, empieza con Cómo Funciona una REST API.
Objetivo
Después de leer esta guía, entenderás:
- Por qué el versionado es esencial para cualquier API que evolucione
- Cómo identificar cambios que rompen vs. cambios que no rompen
- Los pros y contras de diferentes estrategias de versionado
- Cómo aplicar versionado semántico a APIs
- Qué significa deprecation y cómo anunciarlo correctamente
- El ciclo de vida completo de una versión de API desde el lanzamiento hasta el sunset
Tendrás un marco de trabajo para tomar decisiones de versionado y comunicar cambios a los consumidores de tu API.
1. Por Qué Versionar APIs
Toda API evoluciona. Se añaden funcionalidades, se corrigen bugs, y a veces el diseño necesita cambiar fundamentalmente. Sin versionado, tienes dos opciones malas:
Opción A: Romper a todos
graph LR
A[Cambio de API Desplegado] --> B[Todos los Clientes Fallan]
B --> C[Avalancha de Tickets de Soporte]
B --> D[Los Usuarios Pierden Confianza]
B --> E[Impacto en el Negocio]
style A fill:#ffccbc
style B fill:#ffcdd2
style C fill:#ffcdd2
style D fill:#ffcdd2
style E fill:#ffcdd2Opción B: No cambiar nada nunca
Tu API queda congelada, acumulando deuda técnica e incapaz de corregir errores de diseño. Las nuevas funcionalidades se añaden de forma forzada, y la API se vuelve más difícil de usar con el tiempo.
La solución: Versionado
graph LR
A[v2 Lanzada] --> B[v1 Sigue Funcionando]
A --> C[Nuevos Clientes Usan v2]
B --> D[Clientes Existentes No Afectados]
C --> E[Migración Gradual]
D --> F[Usuarios Contentos]
E --> F
style A fill:#c8e6c9
style B fill:#c8e6c9
style F fill:#c8e6c9El versionado te da un contrato: “Esta versión se comporta de esta manera, y no romperé ese comportamiento.”
Qué Dispara una Nueva Versión
No todo cambio requiere una nueva versión. Necesitas una nueva versión cuando haces breaking changes—cambios que causarían que los clientes existentes fallen.
| Tipo de Cambio | ¿Nueva Versión? |
|---|---|
| Eliminar un campo | Sí |
| Renombrar un campo | Sí |
| Cambiar el tipo de un campo | Sí |
| Cambiar un campo requerido a opcional | Quizás (depende del contexto) |
| Cambiar un campo opcional a requerido | Sí |
| Cambiar el formato de respuesta de error | Sí |
| Añadir un nuevo campo | No |
| Añadir un nuevo endpoint | No |
| Añadir un nuevo parámetro opcional | No |
| Corregir un bug | No (normalmente) |
La regla es simple: Si el código del cliente existente rompería, es un breaking change.
2. Cambios que Rompen vs. Cambios que No Rompen
Entender qué constituye un breaking change es crucial para la gobernanza de APIs.
Breaking Changes (Requieren Nueva Versión)
graph TD
A[Breaking Changes] --> B[Cambios de Campo]
A --> C[Cambios de Comportamiento]
A --> D[Cambios de Contrato]
B --> B1[Eliminar campo]
B --> B2[Renombrar campo]
B --> B3[Cambiar tipo]
C --> C1[Cambiar reglas de validación]
C --> C2[Cambiar lógica de negocio]
C --> C3[Cambiar códigos de error]
D --> D1[Cambiar método de auth]
D --> D2[Cambiar params requeridos]
D --> D3[Cambiar estructura de respuesta]
style A fill:#ffcdd2
style B fill:#fff9c4
style C fill:#fff9c4
style D fill:#fff9c4Ejemplo: Eliminación de Campo
// Respuesta v1
{
"id": 123,
"name": "Alice",
"email": "[email protected]",
"phone": "+1-555-1234" // Los clientes pueden depender de esto
}
// Respuesta v2 (breaking: phone eliminado)
{
"id": 123,
"name": "Alice",
"email": "[email protected]"
}
Cualquier código de cliente que acceda a response.phone ahora fallará.
Ejemplo: Cambio de Tipo
// Respuesta v1
{
"price": "29.99" // String
}
// Respuesta v2 (breaking: cambiado a número)
{
"price": 29.99 // Number
}
Los clientes que parsean el precio como string romperán.
Ejemplo: Campo Requerido Añadido
// Request v1 (funciona)
{
"name": "Producto",
"price": 29.99
}
// Request v2 (breaking: category ahora requerido)
{
"name": "Producto",
"price": 29.99,
"category": "electronics" // Requerido en v2
}
El código de cliente existente no enviará category, causando errores de validación.
Non-Breaking Changes (Sin Nueva Versión)
graph TD
A[Non-Breaking Changes] --> B[Cambios Aditivos]
A --> C[Relajar Restricciones]
A --> D[Cambios Internos]
B --> B1[Añadir nuevo campo]
B --> B2[Añadir nuevo endpoint]
B --> B3[Añadir param opcional]
C --> C1[Hacer opcional lo requerido]
C --> C2[Expandir valores válidos]
C --> C3[Aumentar límites]
D --> D1[Mejoras de rendimiento]
D --> D2[Corrección de bugs]
D --> D3[Refactoring interno]
style A fill:#c8e6c9
style B fill:#e8f5e9
style C fill:#e8f5e9
style D fill:#e8f5e9Ejemplo: Añadir Campos
// Respuesta v1
{
"id": 123,
"name": "Alice"
}
// Sigue siendo v1 (non-breaking: campo añadido)
{
"id": 123,
"name": "Alice",
"avatar_url": "https://..." // Nuevo campo, los clientes pueden ignorarlo
}
Los clientes bien diseñados ignoran campos desconocidos, así que esto es seguro.
Ejemplo: Nuevo Endpoint
# Endpoints existentes sin cambios
GET /users
GET /users/:id
# Nuevo endpoint añadido (non-breaking)
GET /users/:id/preferences
Los clientes existentes no llaman al nuevo endpoint, así que no se ven afectados.
Las Zonas Grises
Algunos cambios caen en zonas grises:
Cambiar valores por defecto:
- Si los clientes dependen del valor por defecto anterior, es breaking
- Si es realmente solo una optimización interna, podría ser seguro
Cambiar mensajes de error (no códigos):
- Generalmente seguro si los clientes usan códigos de error, no strings de mensaje
- Breaking si los clientes parsean mensajes de error
Añadir valores a un enum:
- Seguro si los clientes manejan valores desconocidos gracefully
- Breaking si los clientes tienen switch statements exhaustivos
Buena práctica: En caso de duda, trátalo como breaking.
3. Estrategias de Versionado
Hay varias formas de indicar qué versión de API quiere un cliente.
Versionado en Path de URL (Recomendado)
GET /v1/users
GET /v2/users
# URL completa
https://api.example.com/v1/users
https://api.example.com/v2/users
graph LR
A[Request del Cliente] --> B{Path de URL}
B -->|/v1/users| C[Handler v1]
B -->|/v2/users| D[Handler v2]
C --> E[Respuesta v1]
D --> F[Respuesta v2]
style A fill:#e3f2fd
style C fill:#fff9c4
style D fill:#c8e6c9Pros:
- Muy visible: La versión está justo en la URL
- Fácil de probar: Solo cambia la URL en tu navegador
- Routing simple: Enruta diferentes versiones a diferentes handlers
- Amigable con caché: URLs diferentes = claves de caché diferentes
- Documentación clara: Cada versión tiene endpoints distintos
Contras:
- Contaminación de URL: Todas las URLs cambian con cada versión
- Posible duplicación de código: Puede necesitar handlers separados por versión
- Versiona el recurso, no la representación: Filosóficamente impuro
Cuándo usar: La mayoría de APIs. Esta es la opción por defecto por simplicidad y visibilidad.
Versionado Basado en Headers
GET /users
Accept: application/vnd.example.v1+json
GET /users
Accept: application/vnd.example.v2+json
O con un header personalizado:
GET /users
X-API-Version: 1
GET /users
X-API-Version: 2
Pros:
- URLs limpias: Misma URL para todas las versiones
- Cumple HTTP: Usa negociación de contenido como fue diseñado
- Identidad del recurso preservada: La URL identifica el recurso, no la versión
Contras:
- Menos visible: Versión oculta en headers
- Más difícil de probar: No puedes solo pegar la URL en el navegador
- Fácil de olvidar: Los clientes pueden omitir el header
- Complejidad de caché: Necesitas variar el caché por headers
Cuándo usar: Cuando priorizas URLs limpias y tienes clientes sofisticados.
Versionado por Query Parameter
GET /users?version=1
GET /users?version=2
Pros:
- La versión es visible en la URL
- Fácil cambiar de versión
Contras:
- Mezcla concerns: Los query params son para filtrar, no para versionar
- Problemas de caché: Los query params pueden afectar el caching impredeciblemente
- Opcional por naturaleza: Fácil de olvidar
Cuándo usar: Raramente. Generalmente no recomendado.
Comparación de Estrategias
| Estrategia | Visibilidad | Testabilidad | Caché | Pureza |
|---|---|---|---|---|
| URL Path | Alta | Fácil | Simple | Baja |
| Header | Baja | Difícil | Complejo | Alta |
| Query Param | Media | Fácil | Problemático | Baja |
Recomendación: Empieza con versionado en URL path. Es la opción más práctica para la mayoría de equipos.
4. Versionado Semántico para APIs
El Versionado Semántico (SemVer) proporciona una forma estructurada de comunicar el impacto de los cambios.
El Formato MAJOR.MINOR.PATCH
v2.3.1
│ │ │
│ │ └── PATCH: Corrección de bugs (retrocompatible)
│ └──── MINOR: Nuevas funcionalidades (retrocompatible)
└────── MAJOR: Breaking changes
Aplicando SemVer a APIs
Versión MAJOR (breaking changes):
- Incrementa cuando haces cambios incompatibles en la API
- Los clientes deben actualizar su código para usar la nueva versión
# Bump de versión major: v1 → v2
GET /v1/users → GET /v2/users
# Breaking change: campo eliminado
# v1: {"id": 1, "name": "Alice", "phone": "..."}
# v2: {"id": 1, "name": "Alice"} ← phone eliminado
Versión MINOR (nuevas funcionalidades):
- Incrementa cuando añades funcionalidad de forma retrocompatible
- Los clientes pueden seguir usando las funcionalidades existentes sin cambios
# Bump de versión minor: v2.1 → v2.2
# Nuevo endpoint añadido
POST /v2/users/:id/preferences # Nuevo en v2.2
# Nuevo campo opcional añadido
# v2.1: {"id": 1, "name": "Alice"}
# v2.2: {"id": 1, "name": "Alice", "avatar": "..."} ← opcional, aditivo
Versión PATCH (corrección de bugs):
- Incrementa cuando haces correcciones de bugs retrocompatibles
- Sin cambios en el contrato de la API, solo correcciones internas
# Bump de patch: v2.2.0 → v2.2.1
# Corregido: POST /users ahora devuelve 201 en vez de 200 (era un bug)
# Corregido: El header de rate limit faltaba en algunas respuestas
SemVer en URL vs. Headers
La mayoría de APIs solo exponen la versión major en la URL:
# URL muestra versión major
GET /v2/users
# Versión completa en header de respuesta
X-API-Version: 2.3.1
Esto mantiene las URLs simples mientras comunica la versión completa.
Árbol de Decisión de Versionado
flowchart TD
A[Hiciste un cambio en la API] --> B{¿Elimina o modifica
comportamiento existente?}
B -->|Sí| C{¿Los clientes existentes romperán?}
B -->|No| D{¿Añadiste nuevas funcionalidades?}
C -->|Sí| E[Bump de versión MAJOR]
C -->|No| F[Revisar cuidadosamente
probablemente MINOR]
D -->|Sí| G[Bump de versión MINOR]
D -->|No| H{¿Corrección de bug?}
H -->|Sí| I[Bump de versión PATCH]
H -->|No| J[Sin cambio de versión
solo interno]
style E fill:#ffcdd2
style G fill:#fff9c4
style I fill:#c8e6c9
style J fill:#e8f5e95. Deprecation: Anunciando el Final
Deprecation es un aviso de que una funcionalidad o versión será eliminada en el futuro. Es un contrato social con los consumidores de tu API.
Qué Significa Deprecation
timeline
title Ciclo de Vida de una Versión de API
section Activa
v1 Lanzada : Totalmente soportada
v1 Activa : Correcciones de bugs, parches de seguridad
section Deprecated
v1 Deprecated : Aviso emitido
v1 Deprecated : Período de migración (6-12 meses)
section Sunset
v1 Sunset : Versión eliminada
v1 Gone : Devuelve 410 GoneDeprecated = “Esto todavía funciona, pero deja de usarlo.” Sunset = “Esto dejará de funcionar en la fecha X.”
Cómo Anunciar Deprecation
1. Headers de Respuesta
Incluye información de deprecation en cada respuesta:
HTTP/1.1 200 OK
Deprecation: true
Sunset: Sat, 01 Jul 2027 00:00:00 GMT
Link: <https://api.example.com/v2/users>; rel="successor-version"
X-Deprecation-Notice: Esta versión está deprecated. Migra a v2 antes del 1 de julio de 2027.
2. Documentación
Actualiza tu documentación de API de forma prominente:
## Versión 1 (Deprecated)
> **Aviso:** API v1 está deprecated y será eliminada el 1 de julio de 2027.
> Por favor migra a [v2](/docs/v2) lo antes posible.
### Guía de Migración
Ver nuestra [guía de migración de v1 a v2](/docs/migration/v1-to-v2).
3. Anuncios en Changelog
## 2026-01-15: Aviso de Deprecation de v1
API v1 está ahora deprecated. Fechas clave:
- **Hoy**: v1 marcada como deprecated
- **1 de abril de 2027**: v1 entra en período de sunset (SLA reducido)
- **1 de julio de 2027**: v1 eliminada
### Qué Necesitas Hacer
1. Revisar los breaking changes en la [guía de migración](/docs/migration)
2. Actualizar tu integración para usar endpoints v2
3. Probar en staging antes del 1 de julio de 2027
### Breaking Changes en v2
- Campo `phone` eliminado de la respuesta de User
- `created` renombrado a `created_at`
- Formato de respuesta de error cambiado
Mejores Prácticas de Deprecation
| Práctica | Mínimo | Recomendado |
|---|---|---|
| Período de aviso | 3 meses | 6-12 meses |
| Avisos en headers | En endpoints deprecated | En todas las respuestas |
| Notificación por email | Una vez | Recordatorios mensuales |
| Guía de migración | Básica | Paso a paso con ejemplos |
| Avisos de sunset | En deprecation | Progresivos (30, 14, 7 días) |
Deprecar Campos Individuales
No siempre deprecas versiones enteras. A veces solo un campo:
{
"id": 123,
"name": "Alice",
"phone": "+1-555-1234",
"phone_deprecated": "Usa el array 'phones' en su lugar. Se elimina en v2.5",
"phones": [
{"type": "mobile", "number": "+1-555-1234"}
]
}
O en especificación OpenAPI:
properties:
phone:
type: string
deprecated: true
description: "Deprecated: Usa el array 'phones' en su lugar"
6. Sunset y Eliminación
Sunset es la fase final—la versión dejará de funcionar.
Timeline de Sunset
gantt
title Ciclo de Vida de API v1
dateFormat YYYY-MM-DD
section Desarrollo
v1 Desarrollo :2024-01-01, 2024-06-01
section Activa
v1 Activa :2024-06-01, 2025-06-01
section Deprecated
v1 Deprecated :2025-06-01, 2026-06-01
section Sunset
v1 Período Sunset :2026-06-01, 2026-09-01
v1 Eliminada :milestone, 2026-09-01, 0dEl Header HTTP Sunset
RFC 8594 define el header Sunset:
HTTP/1.1 200 OK
Sunset: Sat, 01 Jul 2027 00:00:00 GMT
Esto indica a los clientes exactamente cuándo el endpoint dejará de funcionar.
Qué Pasa en el Sunset
Opción 1: Devolver 410 Gone
GET /v1/users
HTTP/1.1 410 Gone
Content-Type: application/json
{
"error": {
"code": "API_VERSION_SUNSET",
"message": "API v1 ha sido eliminada. Por favor usa v2.",
"documentation_url": "https://api.example.com/docs/migration",
"sunset_date": "2027-07-01"
}
}
Opción 2: Redirigir a la nueva versión
GET /v1/users
HTTP/1.1 301 Moved Permanently
Location: https://api.example.com/v2/users
Advertencia: Las redirecciones pueden ocultar breaking changes. Usa con cuidado.
Opción 3: Proxy con avisos
Hacer proxy temporalmente de requests antiguos a la nueva versión mientras añades headers de aviso. Este es un enfoque de período de gracia.
Checklist de Sunset
Antes de eliminar una versión:
- Aviso de deprecation enviado hace 6+ meses
- Guía de migración publicada
- Múltiples emails recordatorios enviados
- Las métricas de uso muestran tráfico mínimo
- Equipo de soporte preparado para preguntas
- Respuesta 410 Gone configurada
- Monitorización de respuestas 410 activa
7. Etapas del Ciclo de Vida de una API
Cada versión de API pasa por etapas distintas.
El Ciclo de Vida Completo
stateDiagram-v2
[*] --> Preview
Preview --> Activa: Release GA
Activa --> Deprecated: Nueva versión lanzada
Deprecated --> Sunset: Período de migración termina
Sunset --> [*]: Versión eliminada
Activa --> Activa: Correcciones de bugs, updates menores
Deprecated --> Deprecated: Solo correcciones críticasDefiniciones de Etapas
Preview/Beta
- No para uso en producción
- Puede cambiar sin aviso
- SLA limitado o sin SLA
- Recopilando feedback
X-API-Status: preview
X-API-Warning: Esta API está en preview y puede cambiar sin aviso
Activa (GA)
- Lista para producción
- SLA completo aplica
- Breaking changes requieren nueva versión major
- Correcciones de bugs y funcionalidades menores añadidas
X-API-Status: active
X-API-Version: 2.3.1
Deprecated
- Todavía funcional
- Sin nuevas funcionalidades
- Solo correcciones de seguridad
- Avisos de migración activos
X-API-Status: deprecated
Deprecation: true
Sunset: Sat, 01 Jul 2027 00:00:00 GMT
Sunset
- SLA reducido o ninguno
- Puede estar intermitentemente no disponible
- Avisos agresivos
- Cuenta regresiva hacia la eliminación
X-API-Status: sunset
Sunset: Sat, 01 Jul 2027 00:00:00 GMT
X-Days-Until-Removal: 14
Guías de Duración del Ciclo de Vida
| Etapa | Duración Típica | Nivel de Soporte |
|---|---|---|
| Preview | 1-6 meses | Mejor esfuerzo |
| Activa | 1-3 años | SLA completo |
| Deprecated | 6-12 meses | Solo seguridad |
| Sunset | 1-3 meses | Ninguno |
Gestionando Múltiples Versiones Activas
graph TD
A[API Gateway] --> B{¿Versión?}
B -->|v1| C[Servicio v1
Deprecated]
B -->|v2| D[Servicio v2
Activa]
B -->|v3-preview| E[Servicio v3
Preview]
C --> F[(Base de Datos v1)]
D --> G[(Base de Datos v2)]
E --> G
style C fill:#fff9c4
style D fill:#c8e6c9
style E fill:#e3f2fdBuena práctica: Mantén como máximo 2-3 versiones activas simultáneamente.
Plan de Comunicación del Ciclo de Vida
| Evento | A Quién Notificar | Cómo |
|---|---|---|
| Preview lanzada | Desarrolladores interesados | Blog, changelog |
| GA lanzada | Todos los usuarios de la API | Email, blog, changelog |
| Deprecation | Todos los usuarios de v(N) | Email, headers, dashboard |
| Aviso sunset (30 días) | Usuarios activos de v(N) | Email, headers |
| Aviso sunset (7 días) | Usuarios activos de v(N) | Email, header urgente |
| Versión eliminada | n/a | Respuesta 410 |
Qué Sigue
Esta guía cubrió los fundamentos del versionado y gestión del ciclo de vida de APIs—suficiente para tomar decisiones informadas sobre la evolución de tus APIs.
Para temas más profundos como:
- Gestionar migraciones complejas a través de muchos clientes
- Estrategias de comunicación para breaking changes
- Medir el impacto de los cambios de API
- Gobernanza organizacional para el ciclo de vida de APIs
- Herramientas para gestión automatizada de versiones
Ver el próximo curso: Gobernanza del Ciclo de Vida de APIs.
Términos Relacionados del Vocabulario
Profundiza tu comprensión:
- API Versioning - Visión general de estrategias de versionado
- Breaking Change - Qué hace que un cambio sea breaking
- Deprecation - Marcar funcionalidades para eliminación
- Deprecation Policy - Reglas formales de deprecation
- Semantic Versioning - El sistema MAJOR.MINOR.PATCH
- API Lifecycle - Etapas desde diseño hasta sunset
- Sunset - Fin de vida para versiones de API
- URI Path Versioning - Versión en la URL
- Header-Based Versioning - Versión en headers