Primeros pasos con Spectral

Publicado por Víctor Madrid el

Arquitectura de SolucionesSpectralLinterAPI Linter

En este primer artículo vamos a dar nuestros primeros pasos con una de las herramientas que más me ha sorprendido en los últimos tiempos... Spectral

cabecera---Enmilocalfunciona---Spectral---1400x400px-1

A modo de recordatorio pongo los enlaces a los artículos anteriores :

Este es el índice que se va a utilizar para estructurar este artículo

Durante mi experiencia en el mundo del desarrollo y van ya unos cuantos añitos, he podido confirmar prácticamente cada día la frase:

"Existen tantas formas formas de hacer las cosas como formas hay de beber agua"

camille-brodard-ayGdCbHTzpg-unsplash

Foto de Camille Brodard en Unsplash

Esto significa que existen muchísimas maneras de resolver un mismo problema, lo que significa que al final tendremos muchas posibles soluciones.

Cada solución tendrá sus propias listas de pros y contras (como casi cualquier cosa en la vida) y el contenido de cada una de ellas dependerá de que aspectos se hayan considerado como importantes: facilidad de uso, calidad, seguridad, creatividad, solidez, etc.

Por otro lado, hay que hay que tener en cuenta que es condición humana el hecho de ser propenso a cometer errores de todo tipo. Se sabe que esto está en nuestra naturaleza, que se denomina "falibilidad" y que es muy difícil que lo cambiemos.

Además, hay que considerar que los errores tendrán consecuencias a veces sin importancia y otras veces con implicaciones graves en diversos aspectos.

Así que, a la gran variabilidad en la forma de hacer las cosas, le añadiremos un factor o tasa de probabilidad de que aparezcan errores que además dependerá de la persona que lo está haciendo...jejeje ¡Que miedito!

La forma de resolver un problema o esa forma de hacer las cosas suele venir dada por un conjunto de "reglas no escritas" definidas por nosotros mismos.

Ese conjunto de reglas "no escritas" se genera en base a:

  • Lo que sabemos hasta el momento de encontramos el problema
  • Lo que hemos entendido sobre el problema
  • Nuestra forma de hacer las cosas
  • Lo que se nos acaba de ocurrir
  • Cumplimiento de normativas / convenios
  • Evitar los fallos que hemos cometido otras veces haciendo otras cosas o bien lo mismo
  • ...

Le vamos a dar una vuelta más de tuerca a esto, cuando hemos definido lo anterior y hemos demostrado que funciona normalmente lo apuntamos para hacerlo más veces de igual manera o bien tratamos de explicárselo a alguien para que lo haga de la misma manera

¿os suena?

Pues ese sería el origen de las guías de estilo...

¿Qué es una guía de estilo cuando escribimos código?

Conjunto de convenciones, normas y estilos que se deberían de respetar para hacer una cosa de una determinada manera establecida, en nuestro caso concreto para escribir código fuente.

También se suelen llamar: "guías de código", "estándares de código" o "estilos de programación".

Suele ser dependiente y específica del lenguaje de programación que se haya elegido.

Por ejemplo:

Por lo tanto, si todo el mundo hace uso de guías de estilo dentro de una compañía/organización/equipo se consigue garantizar que exista la misma forma de hacer las cosas y se obtiene:

  • Mayor coherencia en los desarrollos al crear una estandarización de código
  • Reducción del desorden
  • Facilita la detección de ciertos tipos de errores / bugs incluso en fases tempranas
  • Incremento de la legibilidad en el código
  • Mayor facilidad a la hora de realizar mantenimientos
  • Mejora de la calidad
  • Mejora en el rendimiento
  • Detección de ciertas vulnerabilidades a nivel de seguridad
  • Ahorro de tiempo general
  • ...

En definitiva, que algo sea coherente, válido y que tenga cierta calidad.

Ejemplos de aspectos que cubre una guía de estilo

  • Estructura de un documento
  • Indentación
  • Espaciado
  • Comentarios del código
  • Estructura de una sección (parámetros de la paginación)
  • Errores
  • Negociación del contendido
  • Formato (camelcase)
  • Detección de patrones
  • Existencia de elementos
  • Restricciones de valores
  • ...

Como podéis ver...es muy importante seguir una Guía de Estilo

¿Qué es un linter?

Un linter o "lintador" es una herramienta de análisis de código estático que cuando se ejecuta, detecta errores (bugs, malas construcciones, problemas estéticos, código duplicado, seguridad, ...) en el código a través de la sintaxis y proporciona diferentes tipos de visualizaciones para ayudar a entenderlos y de esta forma ayudar en su corrección.

Por lo tanto, es una herramienta que ayuda de la forma más automática que sea posible a seguir las directrices marcadas por una "guía de estilo" definida por una organización / empresa / equipo / particular.

¿Qué es Spectral?

Es un linter open source para JSON/YAML desarrollado por Stopligth que permite realizar comprobaciones en base a un conjunto de reglas definido por el usuario y que tiene un proposito general.

35951800-6167-11e9-8549-03f3c25e6cd4

Por lo tanto, permite implementar y automatizar la validación de tus propias guías de estilo facilitando el encontrar problemas

Referencias:

Características

  • Herramienta CLI (uso desde el terminal)
  • Gratuita
  • Se puede utilizar con cualquier documento JSON o YAML : ficheros de configuración, colecciones de Postman, ficheros OpenAPI, fichero de acción de Github, etc.
  • Permite la creación de reglas personalizadas
  • Proporciona un Domain Specific Language para el diseño de las reglas custom
  • Muy popular en su uso para el diseño de APIs : JSON Schema, Open API 2/3 y AsyncAPI 2
  • Integración con algunos editores / IDE (Por ejemplo : Visual Studio Code)
  • Tiene un JavaScript API que facilite escribir test para validar el funcionamiento de las reglas personalizadas
  • Proporciona un conjunto básico de funciones (core functions)
  • Proporciona por defecto varios rulesets y funciones para trabajar con Open API 2/3 y AsyncAPI 2 que se pueden usar o ampliar
  • Proporciona una integración sencilla en flujo de trabajo de desarrollo
  • Proporciona una integración con CI/CD
  • ...

Instalación de Spectral

Spectral CLI es un módulo de Node.js, por lo tanto, será necesario tener instalado Node

Existen diferentes mecanismos de instalación:

Para NPM

  • Instalación como dependencia global
# Opción 1
npm install -g @stoplight/spectral-cli

Para Yarn

  • Instalación como dependencia global
yarn global add @stoplight/spectral-cli

Para utilizar como binario ejecutable

  • Instalación
curl -L https://raw.githack.com/stoplightio/spectral/master/scripts/install.sh | sh

Para Docker

  • Instalación
# Uso con fichero (requiere un volumen) 
docker run --rm -it -v $(pwd):/tmp stoplight/spectral lint "/tmp/file.yaml" # 

#Uso con una URL 
docker run --rm -it stoplight/spectral lint "${url}"
  • Uso desde un fichero docker-compose
stages:
  - validate

validate_open-api:
  stage: validate
  image:
    name: stoplight/spectral
    entrypoint: [""]
  script:
    - spectral lint file.yaml

Verificar que se ha instalado correctamente

Pasos a seguir:

  • Ejecutar el siguiente comando
spectral --version

Verificar que se muestra la versión del producto

  • Para acceder a la ayuda ejecutar el siguiente comando
spectral --h

Componentes de Spectral

Trabaja con tres componentes :

  • Rulesets (Conjunto de reglas)
  • Rules (Reglas)
  • Functions (Funciones)

Rulesets (Conjunto de reglas)

Documentación

Componente que funciona como contenedor de reglas y funciones -> se suele considerar una colección.

Esta colección puede estar escrita en : JSON, YAML o Javascript.

Spectral necesita hacer uso de un fichero de ruleset para poder realizar el lintado.

Los rulesets se pueden extender por composición, es decir, un ruleset puede hacer uso de otros. Por lo tanto, heredarían sus reglas y/o funciones.

Trae definidas de base algunos rulesets como:

  • "spectral:oas"
  • "spectral:asyncapi"

Cuando se quieran diseñar rulesets a medida habrá que tener en cuenta varias consideraciones durante su diseño :

  • Organización
  • Formato
  • Uso

Rules (Reglas)

Documentación

Componente que funciona como filtro de un objeto respecto al conjunto de valores objetivo y especifican la funcion con la que se van a evaluar para verificar su cumplimiento

Cuando se quiera diseñar rules a medida habrá que tener en cuenta varias consideraciones durante su diseño :

  • Organización
  • Formato
  • Uso

Functions (Funciones)

Documentación

Componente que acepta un valor y devuelve un aviso de error en caso de ser un valor incorrecto

Spectral proporciona un conjunto básico de funciones

Las reglas se crean utilizando una o más de estas funciones básicas

Cuando se quiera diseñar functions a medida habrá que tener en cuenta varias consideraciones durante su diseño :

  • Organización
  • Formato
  • Uso

Existen 2 tipos:

El fichero de Ruleset

El fichero de Ruleset es un fichero que Spectral neceita para configurarse

Un fichero del tipo Ruleset consta de tres partes: Extensiones, Reglas y Funciones

  • Extensiones
  • Reglas
  • Funciones

Extensiones

  • Sección del fichero opcional
  • Facilita que un Ruleset puede extender de otro u otros Ruleset
  • Existen diferentes formas de referencias a otros Rulesets a utilizar : predefinidos, otros ficheros locales, otros ficheros en URL o bien otros módulos de node -> Se ubicará dentro de node_modules y debe de tener una package-json válido

Ejemplo de sección "extends"

extends: 
    # Ejemplo de Ruleset Predefinido 
    - spectral:oas 
    # Ejemplo de Ruleset en fichero local 
    - ./config/spectral.json 
    # Ejemplo de Ruleset en fichero en una URL 
    - https://example.org/api/style.yaml 
    # Ejemplo de Ruleset en módulo de Node.js 
    - some-npm-module 

Reglas

  • Sección del fichero opcional
  • Facilita incorporar nuevas reglas declaradas ad-hoc o desde un fichero externo -> reglas personalizadas
  • Permite cambiar ciertas características de configuración de las reglas referenciadas desde otro Ruleset
  • Cada regla se defina mediante un lenguaje de dominio propio

Ejemplo de una regla custom

rules: 
  schema-names-pascal-case: 
    description: Schema names MUST be written in PascalCase 
    message: "component '' " 
    severity: error 
    given: '$.components.schemas.*~' 
    then: 
        function: casing 
        functionOptions: 
            type: pascal 
  ...

Características de la implementación de regla

  • Cada regla personalidada declarada debe de tener un nombre que lo identifique de forma única (ayuda que el nombre sea descriptivo)
  • La sección "description" ayuda a entender que objetivo tiene la regla
  • La sección "message" definirá el tipo de mensaje que mostrará por consola en caso que de que se encuentre un valor que lo incumpla
  • La sección "severity" indicará el grado de criticidad que significa el incumplimiento de esta regla
  • La sección "given" se trata de la expresión JSONPath que permite localizar aquellos elementos sobre los que aplicará la regla. También se facilita el uso de JSONPath Plus que es una extensión de JSONPath que añade ciertas funcionalidades
  • La sección "then" define la función que se ejecutará sobre los elementos encontrados.
    • Cada función tendrá sus propios parámetros de aplicación
    • Para más información acceder a core-functions

Características de la referencia a un regla

  • Las reglas se pueden desactivar mediante la opción off
extends: 
    spectral:oas 
rules: 
    operation-2xx-response: off
  • Las reglas se pueden activar mediante la opción true
extends: [[spectral:oas, off]]
rules: 
    my-custom-rule: true
  • Las reglas pueden cambiar/sobreescribir la severidad que tienen definida por defecto desde esta sección con uno de los siguientes valores: error, warn, info, hint, and off
extends: 
    spectral:oas 
rules: 
    operation-2xx-response: warn

Enfoques de Diseño

En este apartado se van a enser algunos enfoque de diseño para genera la mejor solución de lintado

  • Enfoques de Diseño para Ruleset
  • Enfoques de Diseño para Rules
  • Enfoques de Diseño para Functions

Enfoques de Diseño para Ruleset

  • Enfoques de la organización del fichero Ruleset
  • Enfoques de formato del fichero Ruleset
  • Enfoques de uso del fichero Ruleset

Enfoques de la organización del fichero Ruleset

Spectral necesita que se defina previamente sobre que organización/estructuración de ficheros de reglas se va a trabajar

Para su organización se tendrá en cuenta :

  • Uso de un fichero por defecto
  • Uso de un fichero custom con todo
  • Uso de un ficheros custom específico

Uso de un fichero por defecto

  • Enfoque single-file -> referenciará a todas las reglas sobre las que aplicará el lintado
  • Considerado por defecto por la herramienta
  • Se suele crear en el mismo directorio de documentos que se quieren lintar
  • Se denomina ".spectral.yaml" o ".spectral.yml"
    • Se suele tambien utilizar en formato JSON o JS
  • Suele aparecer oculto (debido al ".")
  • No se hace necesario indicarlo como parámetro en la ejecución de Spectral

Uso de un fichero custom con todo

  • Enfoque single-file -> referenciará a todas las reglas sobre las que aplicará el lintado
  • Se suele crear en cualquier ubicación de la máquina (aunque normalmente se encuentra cercano a los documentos que se quieren lintar)
  • Se denomina como uno quiera ".yaml"
  • Una propuesta para poder identificarlo podría ser : {identificador}.spectral.yaml (Por ejemplo : acme.spectral.yaml)
  • Se hace necesario indicarlo como parámetro en la ejecución de Spectral

Uso de un ficheros custom específicos

  • Enfoque multiple-files -> Cada fichero referenciará a todas las reglas de un "único tipo" consideradas
  • Se suelen crear en cualquier ubicación de la máquina (aunque normalmente se encuentra cercanos a los documentos que se quieren lintar)
  • Se denominan como uno quiera ".yaml"
  • En este caso y al tratarse de varios ficheros estos se podrían organizar segun las necesidades, funcionalidades y/o contextos
  • Una propuesta para poder identificarlo podría ser : {identificador/contexto}.spectral.yaml (Por ejemplo : headers.spectral.yaml, security.spectral.yaml)
  • Se hace necesario indicarlos (los elegidos) como parámetros en la ejecución de Spectral

Enfoques de formato del fichero Ruleset

Spectral necesita que se defina previamente sobre que formato de ficheros sobre los que aplicará el lintado

Hay de definir si aplicará sobre : JSON o YAML

Enfoques de uso del fichero Ruleset

Spectral necesita que se defina como se hará uso de las reglas

Hay de definir si se utilizará como : fichero/s locales/ globales o bien como URL

Enfoques de Diseño para Rules

  • Enfoques de la organización de Rules

Enfoques de la organización de Rules

  • Enfoque single-file -> referenciará a todas las reglas sobre las que aplicará el lintado
    • Un conjunto de reglas se pueden definir de forma ad-hoc sobre el fichero Ruleset utilizado
    • Un conjunto de reglas se puede definir desde la extensión del fichero Ruleset desde otros ficheros de Ruleset
    • Una regla se puede definir de forma individual desde la extensión del fichero utilizado
  • Se puede crear una agrupación de reglas en directorios según el ámbito de *actuación : seguridad, requerimientos,etc.

Enfoques de Diseño para Functions

  • Enfoques de la organización de Functions

Enfoques de la organización de Functions

  • Se suelen almacenar dentro de un directorio denominado "functions"
  • Se referencian desde el fichero de Ruleset
  • Se puede crear una agrupación de funciones en directorios según el ámbito de *actuación : validaciones, etc.

Aplicar Linting a un documento

Para lanzar el análisis se ejecutará el siguiente comando spectral lint desde el terminal con ciertos parámetros según las necesidades

Ejemplos de ejecución

# Análisis sobre el fichero 'myapifile.yaml' con las reglas por defecto
spectral lint myapifile.yaml

# Análisis sobre el fichero 'myapifile.yaml' con las reglas del fichero "myruleset.yaml"
spectral lint myapifile.yaml --ruleset myruleset.yaml

# Análisis sobre el fichero 'myapifile.yaml' con las reglas por defecto recommended"
spectral lint myapifile.yaml --ruleset oas3-recommended 

spectral lint myapifile.yaml --ruleset oas3-recommended, oas3-security 

# Análisis sobre el fichero 'myapifile.yaml' con las reglas proporcionadas por  la URL : 
spectral lint myapifile.yaml https://example.com/acme/openapi-v3.yaml

# Análisis sobre los ficheros de un directorio dado por una expresion glob  con las reglas del fichero proporcionadas 
spectral lint ./examples/**/*.{json,yml,yaml} --ruleset myruleset.yaml

# Análisis cambiando los requerimientos de severidad
spectral lint myapifile.yaml --fail-severity=error --display-only-failures
spectral lint myapifile.yaml --fail-severity=warn --display-only-failures

Tras el análisis se mostrarán aquellos errores que hayan sido encontrados por consola

  • Detalle de cada error
  • Volumetrías de errores según su tipología

Ejemplo de Uso

Para enseñar a utilizarlo y así practicar se ha habilitado un repositorio, este repositorio se reutilizará para otros artículos con Spectral.

La parte de que tiene que ver con este artículo se encuentra en el apartado de basic/

En el fichero README.md de esta sección nos encontraremos los diferentes escenarios de prueba utilizados en el apartado Uso, conviene entender muy bien las explicaciones de cada uno de ellos.

Conclusiones

Tras contar todo esto, me doy cuenta de que ¿cómo he sido capaz de vivir sin esta herramienta hasta ahora?

Esta herramienta ha cogido mucha importancia últimamente para su uso con el desarrollo de APIs en lo relacionado a trabajar con el fichero de contrato, pero se le puede dar uso para otros tipos de ficheros, de hecho, cualquier fichero JSON o YAML. No sé cuántas lágrimas me hubiera ahorrado con ficheros como: YAML de configuración de Spring-Boot, etc.

Uno de sus puntos fuertes es que resulta una herramienta muy amigable a nivel de usuario a la hora de definir y diseñar reglas propias, pero esto ya lo veremos en el siguiente artículo ;-)

Otro megapunto a destacar que tiene es la gran capacidad de personalización de cada una de las partes implicadas...

Se puede realizar un muy buen gobierno de reglas

Por lo tanto, vamos a tener un validador de nuestras guías de estilo que nos mejorará en nuestros desarrollos la consistencia, el mantenimiento, la seguridad, etc.

Comenzamos nuestro camino con esta herramienta

Autor

Víctor Madrid

Líder Técnico de la Comunidad de Arquitectura de Soluciones en atSistemas. Aprendiz de mucho y maestro de nada. Técnico, artista y polifacético a partes iguales ;-)