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
A modo de recordatorio pongo los enlaces a los artículos anteriores :
- Primeros pasos con Spectral (Parte 1) : Artículo de introducción a la herramienta Spectral que hace uso de diferentes ejemplos y que explica diferentes enfoques de diseño.
- Primeros pasos con Spectral (Parte 2): Implementar una Regla Custom: Artículo que enseñará la forma de crear una regla customizada y usarla mediante una propuesta de procedimiento sobre la forma de hacerse.
- Primeros pasos con Spectral (Parte 3): Desarrollando APIs: Artículo que enseñará a como enfocar Spectral al desarrollo de APIs.
Este es el índice que se va a utilizar para estructurar este artículo
- ¿Qué es una guía de estilo cuando escribimos código?
- ¿Qué es un linter?
- ¿Qué es Spectral?
- Instalación de Spectral
- Componentes de Spectral
- El fichero de Ruleset
- Enfoques de Diseño
- Aplicar Linting a un documento
- Ejemplo de Uso
- Conclusiones
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"
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:
- Guía de estilo de Google para trabajar con Java
- Guía de estilo de Google para trabajar con Python
- Guía de estilo general proporcionada por Wordpress para trabajar con Wordpress
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.
Por lo tanto, permite implementar y automatizar la validación de tus propias guías de estilo facilitando el encontrar problemas
Referencias:
- Repositorio de código del proyecto
- Documentación del proyecto
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)
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)
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)
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:
- Funciones Validadoras de Spectral que viene dadas por la herramienta
- Conviene conocerlas
- Ayudan a ser más efectivos en los desarrollos
- Casi cualquier validación típica se puede hacer con algun de las aquí declaradas
- Funciones Validadores Custom
- Permiten la personalización particular
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