En Resumen
El versionado por URL (/v1/pets) es la estrategia de versionado de API más práctica para la mayoría de los equipos. Es visible, cacheable y fácil de probar. El versionado por cabecera y la negociación de contenido son REST más "puros" pero añaden complejidad. Modern PetstoreAPI utiliza el versionado por URL con versionado semántico y políticas claras de deprecación.
Introducción
Tu API necesita un cambio drástico. Estás cambiando el formato de respuesta para /pets de un array simple a un objeto envuelto con metadatos de paginación. Los clientes existentes se romperán. ¿Qué haces?
Necesitas versionado de API. ¿Pero qué estrategia? ¿Versionado por URL (/v1/pets vs /v2/pets)? ¿Versionado por cabecera (Accept: application/vnd.petstore.v1+json)? ¿Negociación de contenido? Cada enfoque tiene defensores apasionados y opiniones fuertes.
La respuesta: el versionado por URL gana para la mayoría de los equipos. Es pragmático, visible y funciona con todas las herramientas HTTP. El versionado por cabecera y la negociación de contenido son teóricamente más limpios, pero añaden una complejidad que la mayoría de los equipos no necesitan.
Modern PetstoreAPI utiliza el versionado por URL con versionado semántico y políticas claras de deprecación. La versión actual es v1, con v2 planeada para futuros cambios drásticos.
En esta guía, aprenderás las tres estrategias principales de versionado, sus ventajas y desventajas, y cómo implementar el versionado correctamente usando Modern PetstoreAPI como referencia.
Por qué las APIs necesitan versionado
Las APIs evolucionan. Añades características, corriges errores y mejoras diseños. A veces, estos cambios rompen los clientes existentes.
Cambios Drásticos (Breaking Changes)
Cambios que rompen los clientes existentes:
1. Eliminación de campos:
// v1
{"id": "123", "name": "Fluffy", "age": 3}
// v2 (drástico: se eliminó age)
{"id": "123", "name": "Fluffy"}
2. Cambio de tipos de campo:
// v1
{"price": "19.99"}
// v2 (drástico: string a number)
{"price": 19.99}
3. Cambio de estructura de respuesta:
// v1 (array simple)
[{"id": "123"}]
// v2 (drástico: objeto envuelto)
{"data": [{"id": "123"}], "pagination": {...}}
4. Cambio de estructura de URL:
// v1
GET /pet/123
// v2 (drástico: plural)
GET /pets/123
5. Cambio de autenticación:
// v1: Clave API en la consulta
GET /pets?api_key=xxx
// v2 (drástico: token Bearer)
GET /pets
Authorization: Bearer xxx
Cambios No Drásticos (Non-Breaking Changes)
Cambios que no rompen los clientes:
- Adición de nuevos endpoints
- Adición de campos opcionales a las solicitudes
- Adición de nuevos campos a las respuestas (los clientes deberían ignorar los campos desconocidos)
- Adición de nuevos parámetros de consulta
- Adición de nuevos métodos HTTP a recursos existentes
La decisión del versionado
Cuando necesitas un cambio drástico, tienes dos opciones:
1. Forzar a todos los clientes a actualizar - Sencillo pero rompe las integraciones existentes
2. Soportar múltiples versiones - Más trabajo pero mantiene la compatibilidad con versiones anteriores
La mayoría de las APIs públicas eligen la opción 2. El versionado te permite evolucionar la API mientras das tiempo a los clientes para migrar.
Versionado por URL
El versionado por URL coloca el número de versión en la ruta de la URL.
Cómo funciona
GET /v1/pets
GET /v2/pets
La versión forma parte del identificador del recurso. Diferentes versiones son diferentes recursos.
Ventajas
1. Visible y explícito
La versión está en la URL. Puedes verla en logs, historial del navegador y documentación. No hay cabeceras ocultas que recordar.
2. Fácil de probar
curl https://petstoreapi.com/v1/pets
curl https://petstoreapi.com/v2/pets
Puedes probar ambas versiones con simples solicitudes HTTP.
3. Funciona con todas las herramientas HTTP
Los navegadores, cachés, proxies y balanceadores de carga ven URLs diferentes. Pueden enrutar, almacenar en caché y registrar cada versión de forma independiente.
4. Simple para los clientes
Los clientes simplemente cambian la URL. No hay cabeceras personalizadas o lógica de negociación de contenido.
5. Fácil de depreciar
Puedes eliminar los endpoints /v1 sin afectar a /v2.
Desventajas
1. No es "REST puro"
Los puristas de REST argumentan que /v1/pets/123 y /v2/pets/123 son el mismo recurso, por lo que deberían tener la misma URL. La versión debería estar en las cabeceras o en la negociación de contenido.
2. Contaminación de URL
Tu API tiene múltiples espacios de URL: /v1/*, /v2/*, etc.
3. Más difícil versionar recursos individuales
Si quieres versionar solo un endpoint, necesitas versionar toda la API o crear inconsistencias.
Implementación
Versión principal en la URL:
/v1/pets
/v2/pets
No incluyas versiones menores:
❌ /v1.2/pets (demasiado granular)
✅ /v1/pets (solo versión principal)
Usa el versionado semántico internamente:
- v1.0.0 - Lanzamiento inicial
- v1.1.0 - Añadir nuevos campos (no drástico)
- v1.2.0 - Añadir nuevos endpoints (no drástico)
- v2.0.0 - Cambios drásticos (nueva URL: /v2)
Modern PetstoreAPI utiliza el versionado por URL con /v1 como la versión actual.
Versionado por cabecera
El versionado por cabecera coloca la versión en una cabecera HTTP personalizada.
Cómo funciona
GET /pets
API-Version: 1
GET /pets
API-Version: 2
La URL permanece igual. La cabecera especifica la versión.
Ventajas
1. URLs limpias
/pets es lo mismo para todas las versiones. Sin prefijo /v1 o /v2.
2. Más "RESTful"
El identificador del recurso (/pets/123) no cambia. La representación cambia según la cabecera.
3. Versionado granular
Puedes versionar recursos individuales:
GET /pets
API-Version: 2
GET /orders
API-Version: 1
Desventajas
1. Invisible
La versión no está en la URL. No puedes verla en los logs o el historial del navegador sin revisar las cabeceras.
2. Más difícil de probar
curl -H "API-Version: 1" https://petstoreapi.com/pets
curl -H "API-Version: 2" https://petstoreapi.com/pets
Debes recordar incluir la cabecera.
3. Complejidad del almacenamiento en caché
Las cachés deben considerar la cabecera API-Version. Necesitas Vary: API-Version en las respuestas.
4. Complejidad del cliente
Los clientes necesitan lógica de cabecera personalizada. No todos los clientes HTTP facilitan esto.
5. Ambigüedad de la versión predeterminada
¿Qué ocurre si el cliente no envía la cabecera? Necesitas un valor predeterminado, lo que crea un comportamiento implícito.
Implementación
Cabecera personalizada:
API-Version: 1
O usa la cabecera Accept:
Accept: application/vnd.petstore.v1+json
Incluir cabecera Vary:
Vary: API-Version
Esto le dice a las cachés que consideren la cabecera al almacenar en caché.
Negociación de Contenido
La negociación de contenido utiliza la cabecera Accept con tipos de medios personalizados.
Cómo funciona
GET /pets
Accept: application/vnd.petstore.v1+json
GET /pets
Accept: application/vnd.petstore.v2+json
La versión forma parte del tipo de medio.
Ventajas
1. Más "RESTful"
Así es como se diseñó REST. Diferentes representaciones del mismo recurso.
2. Sigue los estándares HTTP
Utiliza la negociación de contenido estándar de HTTP.
3. Soporta múltiples formatos
Puedes versionar y formatear simultáneamente:
Accept: application/vnd.petstore.v1+json
Accept: application/vnd.petstore.v1+xml
Desventajas
1. Complejo
Los clientes deben entender los tipos de medios y la negociación de contenido.
2. Más difícil de probar
curl -H "Accept: application/vnd.petstore.v1+json" https://petstoreapi.com/pets
3. Soporte deficiente de herramientas
Muchos clientes y herramientas HTTP no manejan bien los tipos de medios personalizados.
4. Complejidad del almacenamiento en caché
Las cachés deben considerar la cabecera Accept. Necesitas Vary: Accept.
5. Excesivo para la mayoría de las APIs
La mayoría de las APIs no necesitan este nivel de sofisticación.
Implementación
Tipo de medio específico del proveedor:
Accept: application/vnd.petstore.v1+json
Respuesta:
Content-Type: application/vnd.petstore.v1+json
Vary: Accept
Cómo Modern PetstoreAPI implementa el versionado
Modern PetstoreAPI utiliza el versionado por URL con políticas claras.
Versión actual: v1
https://petstoreapi.com/v1/pets
https://petstoreapi.com/v1/orders
https://petstoreapi.com/v1/users
Todos los endpoints están bajo /v1.
Cabecera de respuesta de versión
Cada respuesta incluye la versión de la API:
X-API-Version: 1.2.0
Esto muestra la versión exacta (major.minor.patch) aunque la URL solo muestre la versión principal.
Advertencias de Deprecación
Cuando una versión es deprecada, las respuestas incluyen:
Deprecation: true
Sunset: Sat, 31 Dec 2026 23:59:59 GMT
Link: <https://docs.petstoreapi.com/migration/v1-to-v2>; rel="deprecation"
Deprecation- Indica que la versión está deprecadaSunset- Cuándo se eliminará la versiónLink- Guía de migración
Descubrimiento de versiones
El endpoint raíz enumera las versiones disponibles:
GET https://petstoreapi.com/
{
"versions": [
{
"version": "v1",
"status": "current",
"docsUrl": "https://docs.petstoreapi.com/v1"
}
]
}
Versionado Semántico
Modern PetstoreAPI sigue el versionado semántico internamente:
- Mayor (v1, v2) - Cambios drásticos, nueva URL
- Menor (v1.1, v1.2) - Nuevas características, compatible con versiones anteriores
- Parche (v1.1.1, v1.1.2) - Corrección de errores, compatible con versiones anteriores
Solo las versiones principales aparecen en las URLs.
Probando versiones de API con Apidog
Apidog te ayuda a probar múltiples versiones de API.
Importar múltiples versiones
Importa las especificaciones OpenAPI para cada versión:
petstore-v1.yaml → Entorno: v1
petstore-v2.yaml → Entorno: v2
Ejecutar pruebas contra todas las versiones
Crea suites de prueba que se ejecuten contra ambas versiones:
// Probar v1
pm.environment.set("baseUrl", "https://petstoreapi.com/v1");
pm.sendRequest(pm.environment.get("baseUrl") + "/pets");
// Probar v2
pm.environment.set("baseUrl", "https://petstoreapi.com/v2");
pm.sendRequest(pm.environment.get("baseUrl") + "/pets");
Validar el comportamiento específico de la versión
Comprueba que v1 y v2 se comportan de manera diferente:
// v1 devuelve un array simple
pm.test("v1 devuelve un array", function() {
pm.expect(pm.response.json()).to.be.an('array');
});
// v2 devuelve un objeto envuelto
pm.test("v2 devuelve un objeto envuelto", function() {
pm.expect(pm.response.json()).to.have.property('data');
pm.expect(pm.response.json()).to.have.property('pagination');
});
Comprobar cabeceras de deprecación
Prueba que las versiones obsoletas incluyen las cabeceras adecuadas:
pm.test("La versión obsoleta incluye cabeceras", function() {
pm.response.to.have.header("Deprecation");
pm.response.to.have.header("Sunset");
});
Estrategia de deprecación de versiones
Cómo dejar de usar versiones antiguas sin romper los clientes.
1. Anunciar la deprecación con antelación
Avisa a los clientes con al menos 6-12 meses de antelación:
Deprecation: true
Sunset: Sat, 31 Dec 2026 23:59:59 GMT
2. Proporcionar una guía de migración
Documenta todos los cambios drásticos y cómo migrar:
Link: <https://docs.petstoreapi.com/migration/v1-to-v2>; rel="deprecation"
3. Monitorizar el uso
Rastrea qué clientes aún usan versiones deprecadas:
X-API-Version: 1.2.0
X-Client-ID: abc123
Contacta directamente con los clientes si es necesario.
4. Apagado gradual
No elimines la versión inmediatamente:
- Meses 1-6: Anunciar la deprecación
- Meses 7-9: Añadir cabeceras de deprecación
- Meses 10-11: Reducir los límites de tasa para la versión deprecada
- Mes 12: Eliminar la versión deprecada
5. Mantener la documentación
Incluso después de la eliminación, mantén la documentación de la versión antigua. Los clientes pueden necesitar consultarla.
Conclusión
El versionado por URL es la estrategia de versionado de API más práctica para la mayoría de los equipos. Es visible, fácil de probar y funciona con todas las herramientas HTTP. El versionado por cabecera y la negociación de contenido son REST más "puros", pero añaden complejidad.
Modern PetstoreAPI utiliza el versionado por URL con /v1 como la versión actual, versionado semántico internamente y políticas claras de deprecación. Este enfoque equilibra el pragmatismo con un buen diseño de API.
Utiliza Apidog para probar múltiples versiones de API, validar el comportamiento específico de la versión y asegurar migraciones fluidas entre versiones.
Preguntas Frecuentes
¿Debo usar el versionado por URL o por cabecera?
Usa el versionado por URL a menos que tengas una razón específica para no hacerlo. Es más simple, más visible y más fácil de probar. El versionado por cabecera es más "RESTful" pero añade una complejidad que la mayoría de los equipos no necesitan.
¿Cuántas versiones debo soportar simultáneamente?
Soporta un máximo de 2 versiones: la actual y la anterior. Soportar más crea una carga de mantenimiento. Da a los clientes de 6 a 12 meses para migrar, luego elimina las versiones antiguas.
¿Debo versionar desde v0 o v1?
Empieza con v1. v0 implica inestabilidad. Si tu API no es lo suficientemente estable para v1, no la publiques todavía.
¿Necesito versionar cada endpoint?
No. Solo versiona cuando hagas cambios drásticos. Si añades nuevos endpoints sin cambiar los existentes, no necesitas una nueva versión.
¿Qué pasa con las versiones menores en las URLs?
No incluyas versiones menores en las URLs. Usa /v1, no /v1.2. Las versiones menores son compatibles con versiones anteriores, por lo que los clientes no necesitan cambiar las URLs.
¿Cómo manejo los errores específicos de una versión?
Corrige los errores en todas las versiones soportadas. Si un error solo existe en v1, corrígelo en v1. No obligues a los clientes a actualizar a v2 para obtener correcciones de errores.
¿Debo usar el versionado semántico?
Sí, internamente. Rastrea las versiones major.minor.patch, pero solo expón las versiones principales en las URLs. Esto te da flexibilidad para cambios no drásticos.
¿Qué pasa si solo necesito versionar un endpoint?
Con el versionado por URL, tendrías que versionar toda la API o crear inconsistencias. Esto es una compensación. La mayoría de los equipos aceptan versionar toda la API por simplicidad.
