
¿Entonces, qué tan difícil puede ser versionar una API? La verdad es que no lo es, pero lo que es duro es mantener un poco de cordura al no caer innecesariamente en un número desconcertante de versiones y subversiones aplicadas a docenas de puntos finales de la API con compatibilidades poco claras.
Business in a box.
Descubre nuestras soluciones.
Habla con nuestro equipo de ventas
Breaking Changes Malos! API Versioning Bueno!
Como sabe cualquiera que haya construido o utilice regularmente una API, tarde o temprano se da cuenta, los cambios disruptivos son muy malos y pueden ser una mancha muy seria en una API que de otro modo sería útil. Un cambio disruptivo es un cambio en el comportamiento de una API que puede romper la integración de un usuario y resultar en mucha frustración y pérdida de confianza entre el proveedor de la API y el usuario. Los cambios disruptivos requieren que los usuarios sean notificados con anticipación (con las correspondientes disculpas) en lugar de un cambio que simplemente aparece, como una nueva y encantadora característica. La forma de evitar esa frustración es versionar una API con garantías del propietario de la API de que no se introducirán cambios sorprendentes dentro de una sola versión.
Entonces, ¿qué tan difícil puede ser versionar una API? La verdad es que no lo es, pero lo que es difícil es mantener algo de cordura al no degradarse innecesariamente en un mareo de versiones y subversiones aplicadas a través de docenas de puntos de acceso de API con compatibilidades poco claras.
Introdujimos la v1 de la API hace tres años y no nos dimos cuenta de que seguiría siendo fuerte hasta el día de hoy. Entonces, ¿cómo hemos continuado proporcionando la mejor API de entrega de correo electrónico durante más de dos años pero mantenemos la misma versión de API? Mientras que hay muchas opiniones diferentes sobre cómo versionar las APIs REST, espero que la historia de nuestra humilde pero poderosa v1 pueda guiarte en tu camino hacia la iluminación del versionado de APIs.
REST Es Mejor
Gobernanza API
Con una convención de versionado seleccionada, teníamos más preguntas. ¿Cuándo aumentaríamos la versión? ¿Qué es un cambio importante? ¿Reversionaríamos toda la API o solo ciertos endpoints? En SparkPost, tenemos varios equipos trabajando en diferentes partes de nuestra API. Dentro de esos equipos, las personas trabajan en diferentes endpoints en diferentes momentos. Por lo tanto, es muy importante que nuestra API sea consistente en el uso de convenciones. Esto era más grande que la versión.
Establecimos un grupo de gobernanza que incluye ingenieros que representan a cada equipo, un miembro del equipo de gestión de producto y nuestro CTO. Este grupo es responsable de establecer, documentar y hacer cumplir nuestras convenciones de API en todos los equipos. Un canal de gobernanza de API en Slack también resulta útil para debates animados sobre el tema.
El grupo de gobernanza identificó varias formas en que se pueden introducir cambios en la API que son beneficiosos para el usuario y no constituyen un cambio importante. Estos incluyen:
Un nuevo recurso o endpoint de API
Un nuevo parámetro opcional
Un cambio en un endpoint de API no público
Una nueva clave opcional en el cuerpo POST de JSON
Una nueva clave devuelta en el cuerpo de respuesta JSON
Por el contrario, un cambio importante incluía cualquier cosa que pudiera romper la integración de un usuario, tal como:
Un nuevo parámetro requerido
Una nueva clave requerida en cuerpos POST
Eliminación de un endpoint existente
Eliminación de un método de solicitud de endpoint existente
Un comportamiento interno materialmente diferente de una llamada API, como un cambio en el comportamiento predeterminado.
The Big 1.0
Mientras documentábamos y discutíamos estas convenciones, también llegamos a la conclusión de que era en el mejor interés de todos (¡incluidos nosotros!) evitar hacer cambios que rompieran el API, ya que gestionar múltiples versiones agrega bastante carga. Decidimos que había algunas cosas que debíamos corregir con nuestro API antes de comprometernos con “v1”.
Enviar un correo electrónico simple requería demasiado esfuerzo. Para “mantener las cosas simples”, actualizamos el cuerpo del POST para asegurar que tanto los casos de uso simples como los complejos estén acomodados. El nuevo formato también era más a prueba de futuro. En segundo lugar, abordamos un problema con el endpoint de Metrics. Este endpoint utilizaba un parámetro “group_by” que cambiaría el formato del cuerpo de respuesta GET de tal manera que la primera clave sería el valor del parámetro group by. Eso no parecía muy RESTful, así que dividimos cada group by en un endpoint separado. Finalmente, auditamos cada endpoint e hicimos cambios menores aquí y allá para asegurar que se conformaran con los estándares.
Documentación Precisa
Es importante tener documentación de API precisa y utilizable para evitar cambios disruptivos, ya sean deliberados o no. Decidimos usar un enfoque simple de documentación de API aprovechando un lenguaje Markdown llamado API Blueprint y gestionar nuestros documentos en Github. Nuestra comunidad contribuye y mejora estos documentos de código abierto. También mantenemos un conjunto de documentos no públicos en Github para APIs internas y puntos de conexión.
Inicialmente, publicamos nuestros documentos en Apiary, una excelente herramienta para prototipar y publicar documentación de API. Sin embargo, incrustar Apiary en nuestro sitio web no funciona en dispositivos móviles, por lo que ahora usamos Jekyll para generar documentos estáticos. Nuestros últimos SparkPost API docs ahora cargan rápidamente y funcionan bien en dispositivos móviles, lo cual es importante para los desarrolladores que no siempre están sentados en su computadora.
Separando Deployment de Release
Aprendimos desde el principio el truco valioso de separar una implementación de un lanzamiento. De esta manera es posible implementar cambios con frecuencia cuando están listos a través de la entrega y despliegue continuos, pero no siempre los anunciamos o documentamos públicamente al mismo tiempo. No es raro para nosotros implementar un nuevo punto de acceso API o una mejora a un punto de acceso API existente y usarlo desde la interfaz de usuario o con herramientas internas antes de documentarlo y soportarlo públicamente. De esa manera, podemos hacer algunos ajustes para la usabilidad o conformidad con los estándares sin preocuparnos por realizar un temido cambio incompatible. Una vez que estamos satisfechos con el cambio, lo añadimos a nuestra documentación pública.
¡Doh!
Es justo admitir que ha habido ocasiones en las que no hemos estado a la altura de nuestros ideales de "sin cambios disruptivos" y vale la pena aprender de ellos. En una ocasión, decidimos que sería mejor para los usuarios si una cierta propiedad tuviera el valor predeterminado verdadero en lugar de falso. Después de implementar el cambio, recibimos varias quejas de usuarios ya que el comportamiento había cambiado inesperadamente. Revertimos el cambio y añadimos una configuración a nivel de cuenta, un enfoque mucho más amigable para el usuario, sin duda.
Ocasionalmente, nos sentimos tentados a introducir cambios disruptivos como resultado de correcciones de errores. Sin embargo, decidimos dejar estas idiosincrasias como están en lugar de arriesgar las integraciones de los clientes por el bien de la consistencia.
Hay casos raros en los que tomamos la seria decisión de hacer un cambio disruptivo, como desaprobar un recurso o método de API en interés de la comunidad de usuarios y solo después de confirmar que hay poco o ningún impacto para los usuarios. Por ejemplo, deliberadamente tomamos la decisión de alterar el comportamiento de respuesta del Suppression API, pero solo después de sopesar cuidadosamente los beneficios y los impactos para la comunidad y comunicar cuidadosamente el cambio a nuestros usuarios. Sin embargo, nunca introduciríamos un cambio que tuviera una posibilidad remota de impactar directamente el envío de un correo electrónico de producción de un usuario.