Herramientas OpenAPI Specification

En este artículo analizamos algunas herramientas que nos van a resultar muy útiles para trabajar con archivos de especificaciones de OpenAPI, tanto con la versión 2.0 (conocida como swagger) como con la versión 3.0.

 

Validación de peticiones y respuestas

En ocasiones nos vamos a encontrar con que hemos seguido el paradigma API First y hemos definido una serie de archivos OAS antes de escribir el código de los microservicios, pero cuando comenzamos a implementarlos y probarlos, aparecen en sus respuestas campos nuevos o con un nombre diferente a los que habíamos definido en los esquemas de las APIs.

Esta situación puede aparecer con mucha frecuencia, ya que - especialmente en una metodología de trabajo agile - es muy habitual que entre sprints se produzcan cambios en la base de datos y que se nos olvide actualizar las especificaciones de las APIs.

Para resolver este problema, podríamos aplicar en el API Gateway políticas de validación de esquemas. El problema es que muchos API Gateways no incluyen estas funcionalidades, o – en caso de que sí las soporten - en ocasiones se centran en validar las peticiones de entrada, y no tanto el body generado en las respuestas.

Si estamos desarrollando los microservicios en Java, podemos utilizar una librería de Atlassian que se llama swagger-request-validator (https://bitbucket.org/atlassian/swagger-request-validator) y que es muy útil para comprobar si las peticiones y las respuestas están alineadas con las especificaciones de la API. Esta librería soporta tanto Swagger como OpenAPI 3.0 e incluye adaptadores para Spring, WireMock, etc.

Para incluir la librería en nuestro proyecto debemos añadir esta dependencia en nuestro pom.xml:

<dependency>
  <groupId>com.atlassian.oai</groupId>
  <artifactId>swagger-request-validator-core</artifactId>
  <version>2.8.3</version>
</dependency>

Para poder utilizar el validador, crearemos una clase de tipo OpenApiInteractionValidator:

OpenApiInteractionValidator validator = OpenApiInteractionValidator
  .createForSpecificationUrl("http://petstore.swagger.io/v2/swagger.json")
  .build();

Una vez creado el validador, podemos verificar que ante una petición y una respuesta, si estas corresponde o no a la especificación:

ValidationReport report = validator.validate(
  SimpleRequest.Builder.get("/v2/store/inventory")
    .withHeader("api_key","12345")
    .build(),
  SimpleResponse.Builder.status(200)
   .withBody("{'param':'value'}")
   .build());

Para comprobar si hay discrepancias, debemos preguntarle al objeto report de la clase ValidationReport :

if (report.hasErrors()) {
  System.out.println("Request or response contains errors:");
  report.getMessages().forEach((m) -> {
    System.out.println(m);
  });
}

La librería tiene algunos problemas al tratar APIs en Swagger 2.0 que utilizan el parámetro additionalProperties, ya que se pueden producir errores de validación indicando de manera incorrecta que hay propiedades no permitidas, cuando en realidad la especificación de la API sí que lo permite.

[Path '/datos_variables/data'] Object instance has properties which are not allowed by the schema: ["capital_asegurado","seguro_vida","tipo"]: []

El problema solo aparece con Swagger 2.0, ya que con OAS 3.0 la librería funciona perfectamente. Afortunadamente existe un workaround que consiste en indicarle al validador que ignore additionalProperties:

validator = OpenApiInteractionValidator.createFor("polizas.yaml")
  .withLevelResolver(LevelResolverFactory.withAdditionalPropertiesIgnored())
  .build();

En esta ruta se puede encontrar el código completo de una serie de pruebas realizadas con swagger-request-validator: https://github.com/jrhuerga/swagger-request-validator-test

Conversión de formato de especificación

Otro escenario que nos vamos a encontrar con alguna frecuencia es la necesidad de pasar una especificación de un formato a otro, por ejemplo desde Swagger 2.0 a OpenAPI 3.0, o de WADL o RAML a Swagger 2.0. Esto puede ocurrir por ejemplo si hemos diseñado las APIs con Swagger 2.0 pero queremos migrarlas a OpenAPI 3.0 para aprovechar nuevas funcionalidades. También puede ocurrir lo contrario: que hayamos usado desde el principio OpenAPI 3.0 pero que necesitemos pasar las APIs a Swagger 2.0 si por ejemplo queremos utilizar alguna librería o utilidad que no soporte aún OpenAPI 3.0 o si por ejemplo estamos migrando a un iPaaS o a un API Manager que no soporta aún OpenAPI 3.0.

Una de las utilidades más prácticas para hacer conversiones de formato es api-spec-converter de LucyBot (https://github.com/LucyBot-Inc/api-spec-converter). Se trata de una aplicación Node.js que ofrece un CLI que nos va a permitir cambiar el formato de especificación de una API.

Para instalar la utilidad, lanzaremos esta instrucción:

npm install -g api-spec-converter

Si invocamos a api-spect-converter con el parámetro –h podremos comprobar qué opciones ofrece:

$ api-spec-converter –h
Usage: api-spec-converter [options] <URL|filename>

Convert API descriptions between popular formats.

  Supported formats:
    * swagger_1
    * swagger_2
    * openapi_3
    * api_blueprint
    * io_docs
    * google
    * raml
    * wadl

Options:
  -V, --version                output the version number
  -f, --from <format>          Specifies format to convert
  -t, --to <format>            Specifies output format
  -s, --syntax [outputSyntax]  Specifies output data syntax: json or yaml
  -o, --order [sortOrder]      Specifies top fields ordering: alpha or default openapi
  -c, --check                  Check if result is valid spec
  -d, --dummy                  Fill missing required fields with dummy data
  --passthrough <keyvalue>     Pass an option to the underlying converter (default: {})
  -h, --help                   output usage information

Así si tenemos por ejemplo el archivo polizas.yaml en formato OAS 3.0 y lo queremos pasar a Swagger 2.0, lanzaremos esta instrucción:

$ api-spec-converter --from=openapi_3 --to=swagger_2 --syntax=yaml ..\oas3\polizas.yaml > polizasOAS2.yaml

Comparación entre versiones de APIs

Otro escenario que nos vamos a encontrar es que necesitemos averiguar en qué difieren dos versiones de una misma API. Así, puede que tengamos la versión 1.0.0 de una API, pero que hayamos liberado la versión 1.1.0 donde hemos incorporado algunos cambios retrocompatibles, por ejemplo añadiendo algunos recursos o algunos verbos.

Si queremos comparar ambas especificaciones, una solución inmediata podría ser utilizar las funciones de comparación del editor de texto o las del sistema operativo (diff). No obstante, si necesitamos un informe algo más preciso y que no se vea contaminado ante posibles cambios menores (por ejemplo reordenación de campos) vamos a necesitar un comparador de APIs especializado.

Una herramienta de comparación de APIs muy interesante es swagger-diff: https://www.npmjs.com/package/swagger-diff . Es importante destacar que la herramienta no soporta aún OAS 3.0 sino que solo puede trabajar con Swagger 2.0.

Para instalarla lanzaremos esta instrucción:

npm install swagger-diff –g

Vemos con –h cuales son sus opciones:

$ swagger-diff -h
Usage: swagger-diff [options] <oldSpec> <newSpec>

Compute diff bewteen two Swagger 2.0 specs

Options:
  -o, --outfile <filename>  The output file, otherwise diff is printed on stdout
  -f, --outformat <format>  The output format, either json or raw, default is json
  -c, --config <filename>   The config file
  --no-color                Disable color in output
  -V, --version             output the version number
  -d, --debug [filter]      Show debug output, by default only swagger-diff debug
  -h, --help                output usage information

Para comprobar su funcionamiento, partiremos de un documento Swagger que contiene esta definición para el esquema de Poliza:

definitions:
  Poliza:
    description: Una poliza
    properties:
      apellido_cliente:
        example: Garcia
        type: string
      id:
        example: 123
        format: int32
        type: integer
      datos_variables:
        $ref: '#/definitions/DatosVariables'
      nombre_cliente:
        example: Antonio
        type: string
    title: Poliza
    type: object

Sobre dicho Swagger, añadiremos una propiedad nueva que llamaremos apellido2_cliente:

   apellido2_cliente:
        example: Gonzalez
        type: string

Lanzaremos el comparador y comprobaremos que ha detectado correctamente que se ha añadido una nueva propiedad:

$ swagger-diff polizas100.yaml polizas101.yaml
swagger-diff
Errors (0)
Warnings (1)
add-optional-object-property  definitions/Poliza - Optional property apellido2_cliente added

Generación de portales de documentación

Aunque la mayor parte de las herramientas de API Management como Mulesoft Anypoint incorporan potentes portales de APIs, algunos clientes - que todavía no se han decidido en adquirir una - se encuentran con la situación de que tienen almacenados en un repositorio documentos YAML o JSON con especificaciones de APIs, pero no disponen de un medio conveniente para ofrecer a desarrolladores internos o externos la posibilidad de consultar la documentación de las APIs.

En estos casos, una alternativa puede ser utilizar un portal de APIs open source como Slate (https://github.com/slatedocs/slate). Esta herramienta fue desarrollada en 2013 por Robert Lord, en aquel momento becario en una empresa de software. A partir de ahí, la herramienta ha ido evolucionando en estos 7 años y se utiliza por empresas como Revolut, Coinbase, Best Buy, etc.

El aspecto de los portales generados con Slate es normalmente una única página donde haciendo scroll hacia abajo se accede a la documentación de cada API, y donde la información se presenta en tres paneles:

 

Slate genera el portal a partir de archivos en markdown. Esto implica que antes de poder utilizar Slate, vamos a necesitar utilizar herramientas como Widdershins (https://github.com/Mermade/widdershins) para generar a partir del Swagger 2.0 u OAS 3 archivos de tipo markdown que a su vez puedan ser utilizados para que Slate genere un portal de documentación.

Es habitual utilizar Widdershins y Slate desde pipelines de integración continua, de tal manera que ante un commit en el repositorio donde estén las especificaciones de las APIs, se pueda generar el portal de documentación de manera automática.

Conclusión

A la hora de trabajar con documentos de especificaciones de APIs en Swagger u OpenAPI 3.0 nos va a resultar muy útil el uso de herramientas de validación de peticiones/respuestas, conversores de especificaciones entre formatos, comparadores de especificaciones y generadores de portales de API.

 

Guía de Posibilidades Profesionales en el Ecosistema de Java