En el dinámico mundo de los microservicios, todo puede cambiar: cualquier componente puede reescribirse en otro lenguaje, utilizando diferentes frameworks y arquitecturas. Lo único que debe permanecer inalterado son los contratos, de modo que se pueda interactuar con el microservicio de manera constante, independientemente de las metamorfosis internas. Hoy hablaremos sobre nuestro dilema en la elección del formato de descripción de contratos y compartiremos los artefactos que hemos encontrado.

Publicación preparada por y
Microservicios. Al desarrollar Acronis Cyber Cloud, nos dimos cuenta de que no podíamos escapar de ellos. El diseño de un microservicio es imposible sin la formalización de un contrato, que representa la interfaz del microservicio.
Pero cuando hay más de un componente en el producto y el desarrollo de contratos se convierte en una actividad regular, inevitablemente comienzas a pensar en la optimización del proceso. Se hace evidente que la interfaz (contrato) y la implementación (microservicio) deben coincidir entre sí, que diferentes componentes deben hacer las mismas cosas de la misma manera, y que sin una toma de decisiones centralizada, cada equipo se verá obligado a gastar tiempo una y otra vez en obtenerlas.

Esquema de microservicios de Amazon de de Werner Vogels, CTO de Amazon
¿Cuál es, entonces, el dilema? De facto, existen dos formas de interacción entre microservicios: HTTP Rest y gRPC de Google. No queriendo ser parte del stack tecnológico de Google, elegimos HTTP Rest. Las anotaciones de los contratos HTTP REST a menudo se describen en uno de dos formatos: RAML y OAS, anteriormente conocido como Swagger. Por lo tanto, cada equipo de desarrolladores se enfrenta a la necesidad de elegir uno de los estándares. Pero, como se ha descubierto, hacer esta elección puede ser muy complicado.
¿Por qué son necesarias las anotaciones?
La anotación es necesaria para que un usuario externo pueda entender fácilmente qué se puede hacer con su servicio a través de su interfaz HTTP. Es decir, a nivel básico, la anotación debe contener al menos una lista de los recursos disponibles, sus métodos HTTP, cuerpos de las solicitudes, enumeración de parámetros, indicación de encabezados necesarios y admitidos, así como códigos de respuesta y formatos de respuestas. Un elemento extremadamente importante de la anotación del contrato es su descripción verbal ('¿qué sucederá si se agrega este parámetro de consulta a la solicitud?', '¿en qué caso se devolverá el código 400?')
Sin embargo, cuando se trata del desarrollo de una gran cantidad de microservicios, se desea obtener un beneficio adicional de las anotaciones escritas. Por ejemplo, de RAML/Swagger se puede generar tanto código de cliente como de servidor en una gran cantidad de lenguajes de programación. Además, se puede obtener documentación automáticamente sobre el microservicio y cargarla en su portal de desarrolladores :)

Ejemplo de descripción estructurada del contrato
Es menos común la práctica de probar microservicios basándose en descripciones de contratos. Si ha escrito tanto la anotación como el componente, se puede crear una prueba automática que verifique la adecuación del funcionamiento del servicio con diversos tipos de datos como entrada. ¿El servicio devuelve algún código de respuesta que no esté descrito en la anotación? ¿Podrá manejar correctamente datos manifiestamente incorrectos?
Además, una implementación de calidad no solo de los contratos, sino también de las herramientas para visualizar las anotaciones facilita el trabajo con el microservicio. Es decir, si el arquitecto describió el contrato de manera adecuada, con base en eso, los diseñadores y desarrolladores podrán implementar el servicio en otros productos sin costos de tiempo adicionales.
Para trabajar con herramientas adicionales, tanto RAML como OAS tienen la posibilidad de agregar metadatos no previstos por el estándar ().
En general, el campo para la creatividad en la aplicación de contratos para microservicios es enorme... al menos teóricamente
Comparación entre un erizo y una culebra
Actualmente, la dirección prioritaria de desarrollo en Acronis es el desarrollo de Acronis Cyber Platform. Acronis Cyber Platform son nuevos puntos de integración de servicios externos con Acronis Cyber Cloud y la parte de agente. Aunque nuestras API internas, descritas en RAML, nos satisfacían, la necesidad de publicar la API volvió a plantear la cuestión de elección: ¿qué estándar de anotaciones es mejor utilizar para nuestro trabajo?
Inicialmente parecía que había dos soluciones: las implementaciones más comunes de RAML y Swagger (o OAS). Pero en realidad resultó que hay al menos 3 o más alternativas.
Por un lado está RAML, un lenguaje poderoso y efectivo. Tiene bien desarrollada la jerarquía y herencia, por lo que este formato es más adecuado para grandes empresas que necesitan muchas descripciones, es decir, no un solo producto, sino muchos microservicios que tienen partes comunes de contratos: esquemas de autenticación, tipos de datos similares, cuerpos de errores.
Sin embargo, el desarrollador de RAML, la empresa Mulesoft, se unió al consorcio Open API, que se ocupa del desarrollo . Por lo tanto, el desarrollo de RAML se detuvo. Para imaginar el formato del evento, imagina que los mantenedores de los componentes principales de Linux se fueron a trabajar a Microsoft. Tal situación crea las condiciones para utilizar Swagger, que se está desarrollando dinámicamente y en la última — tercera versión — prácticamente alcanza a RAML en flexibilidad y funcionalidad.
Si no fuera por un pero...
Resulta que no todas las utilidades de código abierto se actualizaron a la versión OAS 3.0. Para los microservicios en Go, la falta de adaptación de a la nueva versión del estándar será lo más crítico. Sin embargo, la diferencia entre Swagger 2 y Swagger 3 es . Por ejemplo, en la tercera versión, los desarrolladores:
- mejoraron la descripción de los esquemas de autenticación
- el soporte para JSON Schema
- mejoraron la capacidad de agregar ejemplos
La situación resulta curiosa: al elegir un estándar, se deben considerar RAML, Swagger 2 y Swagger 3 como alternativas separadas. Solo Swagger 2 tiene un buen soporte de herramientas de OpenSource. RAML es muy flexible... y complicado, mientras que Swagger 3 tiene un débil apoyo de la comunidad, así que tendrás que utilizar herramientas de desarrollo propio o soluciones comerciales, que por lo general son bastante caras.
Sin embargo, si en Swagger hay muchas características agradables, como un portal listo , donde se puede cargar una anotación y obtener su visualización con una descripción detallada, enlaces y relaciones, mientras que para la más fundamental y menos amigable RAML no hay tal posibilidad. Sí, se puede buscar algo entre proyectos en GitHub, encontrar un equivalente y desplegarlo por cuenta propia. Sin embargo, de todos modos, alguien tiene que mantener el portal, lo que no es tan conveniente para un uso básico o necesidades de prueba. Además, swagger es más "pragmático", o liberal — se puede generar a partir de comentarios en el código, lo cual, por supuesto, va en contra del principio de API first y no es compatible con ninguna de las herramientas de RAML.
En su momento comenzamos a trabajar con RAML, como un lenguaje más flexible, y al final tuvimos que hacer muchas cosas manualmente. Por ejemplo, en uno de los proyectos se utiliza la herramienta en pruebas unitarias, que solo admite RAML 0.8. Así que tuvimos que añadir parches para que la herramienta pudiera "aguantar" RAML versiones 1.0.
¿Es necesario elegir?
Después de experimentar escribiendo sobre el ecosistema de soluciones para RAML, llegamos a la conclusión de que necesitamos convertir RAML a Swagger 2 y en él llevar a cabo toda la automatización, verificación, pruebas y posterior optimización. Es una buena manera de usar simultáneamente la flexibilidad de RAML y el soporte de las herramientas de la comunidad de Swagger.
Para resolver esta tarea existen dos herramientas OpenSource, que deberían proporcionar la conversión de contratos:
- – una herramienta actualmente no mantenida. Durante el trabajo con ella, descubrimos que tenía varios problemas con RAML complejos que estaban "dispersos" en una gran cantidad de archivos. Este programa está escrito en JavaScript y realiza un recorrido recursivo por el árbol sintáctico. Debido a la tipificación dinámica, resulta complicado entender este código, así que decidimos no perder tiempo escribiendo parches para una herramienta en declive.
- — una herramienta de la misma compañía, que pretende estar lista para convertir todo y en cualquier dirección. Hasta la fecha, se declare que soporta RAML 0.8, RAML 1.0 y Swagger 2.0. Sin embargo, en el momento de nuestra investigación, la herramienta aún estaba inmadura e impropia para su uso. Los desarrolladores están creando una especie de , lo que les permitirá agregar nuevos estándares rápidamente en el futuro. Pero por ahora, todo esto simplemente no funciona.
Y eso no es todo, con lo que nos hemos encontrado. Uno de los pasos en nuestro pipeline es verificar que el RAML del repositorio es correcto con respecto a la especificación. Hemos probado varias herramientas. Sorprendentemente, todas se quejaron de nuestras anotaciones en diferentes lugares y con palabras totalmente inesperadas. Además, no siempre tenían sentido :).
Al final, nos quedamos con un proyecto obsoleto que también tiene una serie de problemas (a veces falla sin motivo, tiene problemas al trabajar con expresiones regulares). Así que no encontramos una manera de resolver las tareas de validación y conversión con herramientas gratuitas, y decidimos utilizar una herramienta comercial. En el futuro, cuando las herramientas de OpenSource se desarrollen más, puede que resolver esta tarea sea más sencillo. Pero por ahora, el esfuerzo y tiempo invertido en "pulir" la solución nos parecieron más significativos que el costo del servicio comercial.
Conclusión
Después de todo esto, quisimos compartir nuestra experiencia y señalar que antes de elegir una herramienta para describir contratos, es necesario tener claro lo que desean de ella y qué presupuesto están dispuestos a invertir. Si olvidamos el OpenSource, ya hay una gran cantidad de servicios y productos disponibles que pueden ayudar a hacer verificaciones, convertir y validar. Pero son caros, y a veces — muy caros. Para una gran empresa, estos gastos son tolerables, pero para una startup pueden convertirse en una carga significativa.
Definir el conjunto de herramientas que utilizarán más adelante. Por ejemplo, si solo necesitan mostrar un contrato, será más fácil usar Swagger 2, que tiene una API atractiva, ya que en RAML tendrán que levantar y mantener el servicio por su cuenta.
Cuantas más tareas tengan, mayor será la necesidad de herramientas, y estas varían según las plataformas; es mejor familiarizarse con las versiones disponibles desde el principio para tomar una decisión que minimice sus costos en el futuro.
Pero es justo reconocer que todos los ecosistemas existentes hoy en día son imperfectos. Por lo tanto, si hay entusiastas en la empresa que aman trabajar con RAML porque "permite expresar pensamientos de manera más flexible", o, por el contrario, prefieren Swagger porque "es más claro", lo mejor es dejarlos trabajar en aquello con lo que están acostumbrados y quieren, ya que la herramienta de cualquiera de los formatos requiere ajustes finos.
En cuanto a nuestra experiencia, en las siguientes publicaciones hablaremos sobre qué chequeos estáticos y dinámicos realizamos basados en nuestra arquitectura RAML-Swagger, así como sobre la documentación que generamos a partir de los contratos y cómo todo esto funciona.
Solo los usuarios registrados pueden participar en la encuesta. , por favor.
¿Qué lenguaje utilizas para las anotaciones de contratos de microservicios?
RAML 0.8
RAML 1.0
Swagger 2
OAS3 (también conocido como )
Blueprint
Otro
No utilizo
Votaron 100 usuarios. 24 usuarios se abstuvieron.
Fuente: habr.com
