Documenta tus APIs de node (express) con Swagger Autogen fácilmente

Pedro Caicedo
5 min readFeb 26, 2024

--

Swagger en formato ui, json o yaml/yml

Al documentar nuestras APIs estamos ganando tiempo, y facilitando la transferencia de conocimiento. El problema nace cuando esta tarea de documentación (que sabemos es muy valiosa) se hace de forma manual e independiente del código fuente (favoreciendo la desincronización), y dificultando la tarea de documentación. Algo peor de no tener documentación en un proyecto, es que no esté actualizada, y al ejecutar los endpoints no correspondan con la documentación.

Si tienes una API en express, y quieres facilitar su documentación continua a sólo comentarios de código, este post es para tí, así que manos a la obra.

Instalación de las librerías bases

En nuestro proyecto instalamos las librerias de swagger (swagger-autogen y swagger-ui-express) y un transformador de archivos JSON a YAML/YML (js-yaml)para hacer más interoperable la exportación de la documentación auto generada. Para esto ejecutamos el siguiente comando:

npm i --save swagger-autogen swagger-ui-express js-yaml

Configuración de la librería swagger-autogen

En este punto debemos importar la librería swagger-autogen y configurarla en alguno de los dos estandares soportados (Swagger 2.0 ó Open Api 3.x) Nosotros usaremos Open Api 3.x, ya que es el más actual. Esto lo hacemos con el siguiente código:

const autogen = require('swagger-autogen')({openapi: '3.0.0'});

Ahora necesitamos armar la configuración base del proyecto, esto se hace por medio de un JSON. En nuestro caso usaremos un archivo .json que importaremos para mayor orden y legibilidad del código. El formato del archivo es el siguiente:

{
info: {
version: '', // by default: '1.0.0'
title: '', // by default: 'REST API'
description: '' // by default: ''
},
host: '', // by default: 'localhost:3000'
basePath: '', // by default: '/'
schemes: [], // by default: ['http']
consumes: [], // by default: ['application/json']
produces: [], // by default: ['application/json']
tags: [ // by default: empty Array
{
name: '', // Tag name
description: '' // Tag description
},
// { ... }
],
securityDefinitions: {}, // by default: empty object
definitions: {} // by default: empty object
}

Nosotros lo importaremos y lo guardaremos en variable configFile, así:

const configFile = require('./base-config.json');

Creamos ahora la función load donde encapsularemos toda la auto generación del swagger provisto por la librería autogen. Debemos espeficicar donde se guardará la documentación generada en un archivo de salida, nosotros lo guardaremos en la raíz del proyecto en la carpeta docsen el archivo swagger.json. Ademas de especificar las rutas donde se alimentará el auto generador, en nuestro caso usaremos la carpeta routes, donde estan definidos los endpoints de la aplicación, y aprovecharemos para documentarlos; esto lo especificamos en la variable arrEndPointsFiles. Internamente invocaremos a la función autogen cargada, quien se encarga de tomar el archivo de configuración base(configFile) y las rutas de barrido (arrEndPointsFiles), para levantar la documentación, enviandola al archivo de salida (outputFileName). Por último al finalizar la ejecución, transformamos el archivo de salida en formato JSON(.json) a otro archivo YAML/YML (.yml) usando la librería js-yaml. A continuación el código final es el siguiente:

const autogen = require('swagger-autogen')({openapi: '3.0.0'});
const configFile = require('./base-config.json');
const fs = require('fs');

const load = () => {
const outputFileName = '../docs/swagger.json';
const arrEndPointsFiles = [
'../src/routes/*.js',
];

autogen(outputFileName, arrEndPointsFiles, configFile).then(() => {
// JSON to YAML format
const YAML = require('js-yaml');
const jsonFile = require('../../../docs/swagger.json');
const yamlFile = YAML.dump(jsonFile);

// Save YAML file
fs.writeFileSync('./docs/swagger.yml', yamlFile, 'utf8');
});
}

module.exports = load;

Integración del swagger autogen en el flujo inicial de la aplicación principal

Ya que contamos con la función load que nos configura todo el swagger autogen. Debemos invocar la función en el flujo inicial de la aplicación principal para que pueda realizar la carga. Generalmente esto ocurre en el archivo index.js en la raíz del proyecto o en nuestro caso este archivo está ubicado en la carpeta src. Es en este archivo donde se cargan las rutas, midlewares, entre otras configuraciones general de nuestra app. Justo antes de iniciar el servidor web de express hacemos la carga del swagger usando el código a continuación:

// Load swagger support
const swagger = require('./docs/swagger/autogen');
swagger();

Ya en este punto cada vez que se inicie la aplicación, se generarán los archivos .json y .yml con la documentación autogenerada con la librería swagger autogen. Seria bueno que la documentación sea servida a travez de un endpoint.

Disponibilizar la documentación en un endpoint con soporte a UI, JSON y YAML/YML

Ya con la auto generación configurada, podemos disponibilizar los archivos auto generados creados. Además se puede crear una interfaz de usuario usando la librería swagger-ui-express para visualizarlos de forma mucho más amigables. Para lograr esto crearemos un Router encargado de resolver el endpoint ./docs/swagger?format=uicon una variable query param format que permitirá cambiar entre la vista UI (HTML/JS), JSON y YAML/YML. A continuación está el código que permite disponibilizar el servicio.

const { Router } = require('express');
const router = Router();

router.use('/swagger', ui.serve);
router.get('/swagger',
(req, res, next) => {

const format = req.query.format || 'ui';

switch (format) {
case 'json':
// JSON Format
res.json(jsonFile);
break;

case 'yml':
case 'yaml':
// YAML/YML Format
res.set('Content-Type', 'text/plain');
res.sendFile(path.join(__dirname, '../../docs/swagger.yml'));
break;
default:
next();
break;
}
},
ui.setup(jsonFile)
);


module.exports = router;

En este punto tenemos ya el auto generador y el servicio que permite visualizar a travez de un endpoint la documentación. Queda ahora documentar el servicio de manera que la librería swagger autogen la pueda interpretar cuando haga el barrido de los archivos.

Si tomamos como ejemplo el servicio que acabamos de crear que disponibiliza la documentación generada, esto se logra agregando el siguiente comentario debajo de la ruta GET /swagger, así:

/*
#swagger.tags = ["Documentation"]
#swagger.path = "/docs/swagger/"
#swagger.summary = "View documentation on HTML (ui), json or yaml/yml"
#swagger.description = "View documentation on HTML (ui), json or yaml/yml"
#swagger.parameters["format"] = {
in: "query",
description: "It is a swagger doc (default option is ui)",
type: "string",
schema: {
$ref: "#/components/schemas/Format"
}
}

#swagger.responses[200] = {
description: "Respond according to the selected format"
}
*/

Se puede observar que los comentarios tienen un formato específico, siempre llevan el prefijo #swaggercómo descriptor de sentencia. Puedes revisar todas las sentencias válidas en la documentación de la librería swagger autogen y en el estándar open api.

Ahora con esta configuración, la documentación de los endpoints de tus aplicaciones se simplifica a crear un comentario, logrando facilitar la actualización de la documentación de manera viva en el código fuente de nuestras aplicaciones, y es ahora responsabilidad del desarrollador y de sus pares mejora (PR) a mejora (PR) tenerla actualizada.

Les mando un Hola Mundo :), recuerden que el código fuente de este post (con una app completamente funcional) lo pueden revisar acá en github, y si quieren invitarme un café ☕️ (no lo duden) acá, recuerden “menós es más”.

--

--

Pedro Caicedo

Innovador por naturaleza, desarrollador de software de profesión y futbolista de corazón.