Aumenta la calidad de tu API integrando Zally en GitLab CI

José Collado, Software Engineer en EDICOM, nos explica cómo aumentar la calidad de tu API integrando Zally en GitLab. Descubre qué es Zally, cómo integrarlo y algunas de las reglas que nos ha reportado en nuestros proyectos.

    Artículo elaborado por:

    José Collado

    Desarrollador Full Stack

    Desarrollador Full Stack especializado en Angular y Spring Boot, con interés en User Experience y Usabilidad.

Introducción

Actualmente, las empresas de desarrollo de software están dando cada vez más importancia a la calidad de sus productos, así como a la automatización de herramientas que permitan asegurarla.

Un estudio realizado por World Quality Report en el que se incluyen 1200 empresas concluye que un 61% de estas tienen como objetivo clave la calidad de sus soluciones de software. Además, el 51% tienen implementados procesos de Integración Continua para detectar si se cumplen los requisitos de calidad al introducir nuevo código.

Desde EDICOM creemos que la calidad es un elemento esencial a la hora de desarrollar nuestro software, por lo que decidimos apostar por herramientas que nos ayuden a detectar y corregir errores en nuestros productos, como ya vimos con Google Lighthouse.

¿Qué es Zally?

Zally es un linter creado por Zalando que a partir de una especificación de OpenAPI, comprueba si el API cumple las reglas que se incluyen en su guía de buenas prácticas.

Con Zally, aumentaremos la calidad de nuestra API detectando errores y malas prácticas en las primeras fases del desarrollo. Además, nos ayudará a estandarizar nuestras APIs dándoles un look and feel similar a todas ellas.

Aumentar la calidad de tu API integrando Zally en GitLab

Podemos utilizarlo a través de su API RESTful, desde el CLI o desplegando su interfaz web.

En su repositorio de GitHub encontramos una guía de inicio rápido para desplegarlo en local y probarlo.

Integración de Zally en GitLab CI

1. Despliegue de la aplicación con Docker

Como podemos leer en su documentación, Zally es una aplicación cuyo servidor está desarrollado con Spring Boot y la web con React. Para seguir este artículo, necesitaremos como mínimo desplegar la parte del servidor. Existen diferentes formas para ello, aunque la más sencilla es desplegarlo con Docker aprovechando el fichero docker-compose que nos proporcionan ellos y que nos levantará el backend en el puerto 8000 y la interfaz web en el 3000.

2. Generación automática de la especificación de OpenAPI

La aplicación en la que queremos integrar Zally consiste en un backend desarrollado en Spring Boot, por lo tanto utilizaremos el plugin de maven springdoc-openapi-maven-plugin para autogenerar la especificación de OpenAPI en cada pipeline de un Merge Request.

Para ello, deberemos tener configurado previamente en el proyecto el plugin springdoc-openpi.

<plugin>
	<groupId>org.springdoc</groupId>
	<artifactId>springdoc-openapi-maven-plugin</artifactId>
	<version>1.4</version>
	<executions>
		<execution>
			<id>integration-test</id>
			<goals>
				<goal>generate</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<apiDocsUrl>http://localhost:8080/api/v1/api-docs</apiDocsUrl>
		<outputFileName>openapi.json</outputFileName>
		<outputDir>${project.build.directory}</outputDir>
	</configuration>
</plugin>

Esta es la configuración del plugin que incluiremos en el pom.xml, donde apiDocsUrl será la URL local donde estemos generando la especificación OpenAPI con springdoc-openapi.

Si hemos configurado el plugin correctamente, lanzando el comando mvn integration-test nos generará un fichero openapi.json en el directorio de target del proyecto.

{
    "openapi": "3.0.1",
    "info": {
        "title": "Backend Articulo Zally",
        "description": "Descripcion del api REST",
        "version": "v0.1.0-3b6167f"
    },
    "servers": [
        {
            "url": "http://localhost:8080/api/v1",
            "description": "URL API localhost"
        }
    ]
	...

3. Crear stage para Zally

Una vez ya tenemos la especificación de OpenAPI generada en el pipeline del Merge Request, podemos crear un stage en Gitlab CI que llame al servidor de Zally y nos devuelva la validación. Para ello, hemos creado un script de bash que lanza una petición POST con el fichero openapi.json en el cuerpo de la petición:

   LINT_RESPONSE=$(curl -s -X \
        POST $SERVER_URL/api-violations -o output.json \
        --header 'Content-Type: application/json' \
        --data "@body.txt")

Donde body.txt contiene un json con la siguiente estructura:

{
    "api_definition": {},
    "api_definition_string": "",
    "api_definition_url": "",
    "ignore_rules": []
}

Estos son los argumentos que recibe el script y que se le pasarán como variables del CI:

  • $SPEC_LINT_FILE: Fichero con la especificación OpenAPI (en formato JSON o YAML)
  • $SPEC_LINT_URL: Si nuestra especificación no esta en un fichero sino en una URL.
  • $ZALLY_SKIN_URL: URL donde se ubica la interfaz web de Zally.
  • $ZALLY_SERVER_URL: URL del servidor de Zally.
  • $IGNORED_ZALLY_RULES: Ids de las reglas de Zally que queremos deshabilitar, separados por comas.
  • $MUST_THRESHOLD: Umbral a partir del cual queremos que el resultado del stage sea fallido.

Y así llamaremos a la función que hemos creado en el script de bash:

source ./zally-curl-validation.sh
zallylinter -f "$SPEC_LINT_FILE" -u "$SPEC_LINT_URL" -l "$ZALLY_SERVER_URL" -i "$IGNORED_ZALLY_RULES" -t "$MUST_THRESHOLD" -s "$ZALLY_SKIN_URL"

4. Resultado de la validación

La respuesta que recibimos de la petición anterior contiene la validación y tiene la siguiente estructura:

{
    "external_id": "aece171b-42ae-4c3d-8b4e-cef0d0dac9fa",
    "message": "",
    "violations": [
        {
            "title": "Lowercase words with hyphens",
            "description": "Use lowercase separate words with hyphens for path segments",
            "violation_type": "MUST",
            "rule_link": "https://zalando.github.io/restful-api-guidelines/#129",
            "paths": [
                "/paths/~1pet~1findByTags"
            ],
            "pointer": "/paths/~1pet~1findByTags",
            "start_line": null,
            "end_line": null
        },
		...
    ],
    "violations_count": {
        "must": 89,
        "should": 25,
        "may": 1,
        "hint": 0
    },

A continuación indicaremos si el stage debe fallar o no, en función de cantidad de reglas MUST y la variable $MUST_THRESHOLD:

   MUST=$(jq -r '.violations_count.must' <<<"$RESPONSE")
    if [ "$MUST" -gt "$FAIL_THRESHOLD" ]; then
        exit 1
    else
        exit 0
    fi

Para visualizar el reporte desde el skin, concatenamos la URL de la web con el id de la validación obtenido en la respuesta:

echo -e "$SKIN_URL/editor/$EXTERNAL_ID"

Y así quedaría finalmente el resultado de la ejecución:

Aumentar la calidad de tu API integrando Zally en GitLab

Reporte y conclusiones

Finalmente, analizaremos algunas de las reglas que nos ha reportado Zally en nuestros proyectos.

  • Utilizar snake_case para los nombres de propiedades, query params, etc. (Regla 118)
deleteFile -> delete_file
  • Pluralizar los nombres de recursos. (Regla 134)
/deployment -> /deployments
  • Propiedades de tipo fecha deben usar el sufijo «at». (Regla 235)
startTime -> started_at
  • La respuesta de las llamadas deben ser objetos JSON. (Regla 110)
Respuesta con un entero: 215 -> { "total_deployments": "215" }
  • La versión del API debe cumplir el formato Semver. (Regla 116)
<MAJOR>.<MINOR>.<PATCH>

Como vemos, son reglas que corresponden con buenas prácticas de programación y que ayudan a crear estándares que facilitan el consumo de APIs por otros desarrolladores.