Definicion
Las APIs no son estáticas - evolucionan. Necesitas agregar características, corregir defectos de diseño y mejorar el rendimiento. Pero aquí está el problema: otras personas están usando tu API. Si simplemente cambias cosas, sus aplicaciones se rompen. El versionado de APIs resuelve este dilema permitiéndote ejecutar múltiples versiones simultáneamente, dejando que los clientes antiguos sigan funcionando mientras los nuevos obtienen nuevas características.
Piensa en el versionado como ejecutar universos paralelos de tu API. La versión 1 vive en un universo con su diseño original. La versión 2 existe en otro universo con mejoras y nuevas capacidades. Los clientes eligen en qué universo quieren vivir, y tú mantienes ambos hasta que suficientes clientes hayan migrado para que puedas retirar el antiguo.
Hay varias estrategias comunes para el versionado. El versionado por URI pone la versión en la ruta (/api/v1/users), haciéndola altamente visible y simple. El versionado por header usa headers HTTP (Accept: application/vnd.myapi.v2+json), manteniendo las URLs más limpias pero ocultando la versión. El versionado por parámetro de query añade la versión a las peticiones (/api/users?version=2). Cada enfoque tiene compensaciones, pero lo más importante es elegir uno y ser consistente. Tus usuarios nunca deberían tener que adivinar qué versión están usando.
Ejemplo
API de Stripe: Stripe usa versionado basado en fechas donde cada versión de API se identifica por una fecha como 2023-10-16. Cuando creas una cuenta, quedas fijado a la versión de ese día. Puedes actualizar cambiando un header, pero tus integraciones no se romperán inesperadamente.
API de Twitter: Twitter ejecuta v1.1 y v2 simultáneamente. La versión 2 tiene una estructura completamente diferente, pero v1.1 sigue funcionando para clientes que no han migrado todavía. Esto da tiempo a los desarrolladores para actualizar sus apps.
APIs de Google Cloud: Google usa números de versión en rutas (/v1/projects, /v2/projects) y mantiene guías de migración detalladas entre versiones. Anuncian fechas de sunset con mucha anticipación.
API de GitHub: GitHub usa versionado por URL para su API REST y un endpoint estable para GraphQL. Comunican cambios incompatibles a través de su changelog y dan a los desarrolladores meses para prepararse.
Analogia
El iPhone e iOS: Apple lanza nuevos iPhones y versiones de iOS, pero los teléfonos antiguos siguen funcionando. Las apps construidas para iOS 15 todavía corren en iOS 17 (en su mayoría). Apple mantiene compatibilidad hacia atrás mientras agrega nuevas características. El versionado de APIs sigue el mismo principio - las integraciones antiguas siguen funcionando incluso mientras la API mejora.
La Evolución del Menú del Restaurante: Un restaurante podría revisar su menú, agregando nuevos platos y eliminando antiguos. Pero los clientes regulares son avisados con anticipación: “Dejaremos de servir el pollo a la parmesana en 3 meses.” La deprecación de APIs funciona igual - las versiones se anuncian para sunset con suficiente aviso.
El Cierre de Carril de Autopista: Cuando la construcción de autopista necesita cerrar un carril, hay señales que avisan a los conductores kilómetros antes, y el tráfico se desplaza gradualmente. Las APIs hacen lo mismo - anuncian sunsets de versiones, proporcionan rutas de migración, y dan tiempo a los usuarios para la transición.
Los Estándares USB: USB 2.0, 3.0, 3.1 y 4.0 todos coexisten. Los dispositivos más nuevos funcionan con cables más antiguos (a velocidades reducidas). El versionado de APIs apunta a compatibilidad similar - las nuevas versiones agregan capacidades sin romper la funcionalidad básica.
Code Example
// 1. Versionado por URI/Ruta (más común)
GET /api/v1/users/123
GET /api/v2/users/123
// 2. Versionado por header
GET /api/users/123
Accept: application/vnd.myapi.v2+json
API-Version: 2
// 3. Versionado por parámetro de query
GET /api/users/123?version=2
// 4. Negociación de contenido
GET /api/users/123
Accept: application/vnd.myapi+json;version=2
// Ejemplo de detección de versión
app.get('/api/:version/users/:id', (req, res) => {
const version = req.params.version;
if (version === 'v1') {
return v1Handler(req, res);
} else if (version === 'v2') {
return v2Handler(req, res);
}
});
Notas de Seguridad
Requisitos Principales:
- Cada versión de la API debe tener su propia auditoría de seguridad.
- Las versiones antiguas deben tener fechas de finalización y ser deprecadas apropiadamente.
Mejores Prácticas:
- Monitorea el uso de versiones deprecadas y aplica límites de tasa.
- Nunca asumas que las versiones antiguas son “seguras por defecto” - necesitan parches de seguridad continuos..