- Cuando una API web pública usa a la vez un nombre como Product API y una ruta
/api/v1, la versión semántica de la propia API y su estructura pueden desalinearse - Si se usan en paralelo la ruta
/v1/ymajor.minor.patch, se mezclan las rutas con el contrato de la API, y el primer número de la versión semántica queda fijado en la URL - Los cambios que rompen compatibilidad pueden requerir una ruta nueva y rutas de proxy inverso, por lo que la información del contrato puede quedar dispersa entre la URL y el número de versión
- Si se crean APIs posteriores al mismo tiempo, la API existente en la práctica queda atada a
v1, y en cambios posteriores que rompan compatibilidad el significado del nombre y la ruta se vuelve ambiguo - Se plantea la inquietud de encontrar, para el versionado de APIs web públicas, una alternativa menos molesta a este patrón repetido y principios de diseño mejores
¿Quieres seguir recibiendo temas de tecnología seleccionados?
Sigue el canal de Telegram. @GeekNewsES
1 comentarios
Opiniones en Lobste.rs
Poner
/v1/en la URL en realidad tiene una gran ventaja: te obliga a no romper la API para los usuarios hasta que apagues ese endpointOtros textos del mismo autor, como Evolving HTTP APIs, ofrecen consejos útiles
Básicamente, se agrega
/v1/,/v2/, etc. a cada ruta para indicar cambios incompatibles. Si es una API pública operativa y no un estándar que deba funcionar en múltiples hosts, no hay mucha razón para usar versionado semántico completo (semantic versioning)El versionado semántico existe para que otros desarrolladores puedan actualizar dependencias con confianza sin tener que leer el changelog durante 20 minutos, pero en una API en producción la gente no puede elegir cuándo adoptar una nueva versión menor o de corrección
Se considera cambio incompatible cuando se modifica un comportamiento documentado o se rompen clientes existentes que dependen de ese comportamiento documentado. Hay quienes también consideran incompatibles los cambios en comportamientos no documentados, pero eso trae muchos riesgos
En Google lo hacen así: AIP-185: API Versioning, AIP-180: Bacwards compatibility
Siento que estos documentos de diseño están bastante adaptados a la forma de trabajar de Google, pero los he usado como referencia al diseñar APIs y varias de sus ideas me parecieron muy útiles
En general, creo que toda API debería intentar minimizar al máximo los cambios incompatibles. Por ejemplo, si quieres cambiar el nombre de una propiedad, me parece mejor agregar el nombre nuevo en paralelo en vez de eliminar la propiedad anterior
Dicho eso, la forma en que la gente de Buttondown lo hace también es limpia. Definen migraciones entre versiones de la API, de modo que el consumidor puede fijar su versión mediante un header y el proveedor puede seguir haciendo cambios
La respuesta obvia parece ser “el nombre nuevo siempre tiene prioridad”, pero eso puede fallar cuando el cliente hace una secuencia de lectura-modificación-escritura y vuelve a enviar una versión modificada del objeto creado por el servidor. El cliente podría actualizar solo la propiedad vieja y devolver la nueva sin cambios, tal como venía
Parecería que esas transformaciones también podrían usarse para asignación de comportamiento, pero salvo que se me haya pasado algo, eso no se trataba ahí
Idealmente, la versión debería incluirse en la ruta, y las versiones nuevas deberían tener un carácter aditivo. Así, la API de la versión vieja podría reenrutar la solicitud hacia una versión más nueva de la API aplicando las transformaciones de entrada y salida necesarias
Si después de unos años nadie usa una versión antigua, se puede eliminar y la ruta
/v1/pasaría a dar errorHace tiempo leí un poco sobre versionar APIs mediante negociación de contenido con el header
Accept. Si alguien ha versionado APIs de esa forma, me interesaría conocer su experienciaEn mi experiencia, el versionado por recurso o el versionado global han sido de las formas más intuitivas. Para la deprecación, usar el header de respuesta HTTP
Deprecation(RFC 9745) y eventualmente devolver respuestas como410 Goneen endpoints viejos parece una forma razonable de empujar a los clientes a migrar a la nueva versiónAdemás, de verdad me da curiosidad si alguien ha construido una API evolutiva: una que traduzca internamente las solicitudes de versiones antiguas a solicitudes de una versión más nueva de la API, y luego elimine de verdad la versión antigua una vez que los clientes migren o pase cierto tiempo