Versionado y Ciclo de Vida de APIs

Ciclo De Vida Intermediate 18 min Jan 12, 2026

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:#ffcdd2

Opció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:#c8e6c9

El 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
Renombrar un campo
Cambiar el tipo de un campo
Cambiar un campo requerido a opcionalQuizás (depende del contexto)
Cambiar un campo opcional a requerido
Cambiar el formato de respuesta de error
Añadir un nuevo campoNo
Añadir un nuevo endpointNo
Añadir un nuevo parámetro opcionalNo
Corregir un bugNo (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:#fff9c4

Ejemplo: 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:#e8f5e9

Ejemplo: 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:#c8e6c9

Pros:

  • 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

EstrategiaVisibilidadTestabilidadCachéPureza
URL PathAltaFácilSimpleBaja
HeaderBajaDifícilComplejoAlta
Query ParamMediaFácilProblemáticoBaja

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:#e8f5e9

5. 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 Gone

Deprecated = “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ácticaMínimoRecomendado
Período de aviso3 meses6-12 meses
Avisos en headersEn endpoints deprecatedEn todas las respuestas
Notificación por emailUna vezRecordatorios mensuales
Guía de migraciónBásicaPaso a paso con ejemplos
Avisos de sunsetEn deprecationProgresivos (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, 0d

El 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íticas

Definiciones 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

EtapaDuración TípicaNivel de Soporte
Preview1-6 mesesMejor esfuerzo
Activa1-3 añosSLA completo
Deprecated6-12 mesesSolo seguridad
Sunset1-3 mesesNinguno

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:#e3f2fd

Buena práctica: Mantén como máximo 2-3 versiones activas simultáneamente.

Plan de Comunicación del Ciclo de Vida

EventoA Quién NotificarCómo
Preview lanzadaDesarrolladores interesadosBlog, changelog
GA lanzadaTodos los usuarios de la APIEmail, blog, changelog
DeprecationTodos 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 eliminadan/aRespuesta 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: