Ir para o conteúdo principal

Swagger: melhores abordagens para documentação

Data de elaboração 18/08/2021
Responsável pelo estudo
  1. Diego Gonçalves de Almeida (Assessor)
Equipe do estudo Esquadrão Suicida
Alvo Swagger
Origem


  • Objetivo estratégico: Padronização de documentação de APIs
Objetivo Definição da melhor abordagem para padronização de documentações de APIs node.js usando o Swagger no âmbito da Superintendência de Tecnologia da Informação e Comunicação - SETIC. Atualmente, as API's são documentadas usando o Postman que, como tem integração com a _rout_, basta apenas algumas marcações no código-fonte para que a documentação seja gerada. Todavia, com a mudança do Postman para o Swagger, aplicação adotada como padrão no âmbito da SETIC, visando a implementação de dicionário de dados, exemplos de resposta variados abordando diversos casos e também a documentação de erros possíveis, faz-se necessário definir padrões de documentação que não polua o código excessivamente e de fácil manutenção/geração.
Documentação correlata (opcional)

https://www.npmjs.com/package/swagger-ui-express

https://www.npmjs.com/package/swagger-jsdoc

https://dev.to/kabartolo/how-to-document-an-express-api-with-swagger-ui-and-jsdoc-50do

https://www.npmjs.com/package/express-jsdoc-swagger

https://github.com/epiphone/routing-controllers-openapi

Observações Não possui.

    Glossário
    • Swagger: é uma aplicação para auxilio no desenvolvimento de documentações
    • OpenAPI: é uma especificação para documentação de API's Rest agnóstica a linguagem.
    • Node.js - é um ambiente de execução JavaScript open-source que funciona utilizando o mecanismo Chrome V8.
    • JavaScript - é uma linguagem de programação de alto nível que segue as especificações ECMAScript.
    • TypeScript - é um superconjunto sintático estrito de Javascript, criado e mantido pela Microsoft.
    • yarn - é um gerenciador de pacotes javascript.
    • NPM - Node Package Manager.
    1. Introdução

    Maior produtividade na confecção da documentação com o uso de funções já existentes no Typescript, sem prejuízo da manutenção da aplicação, pois o código permanece 'limpo'. Com base nos estudos realizados decidimos utilizar o swagger, diversos times hoje usam esta ferramenta para documentação, logo, tonaria mais fácil a utilização para os mesmos.

    2. Desenvolvimento

    3. Desenvolvimento

    2.1 Swagger UI Express:

    Nos testes  realizados constatamos que esta biblioteca serve como pilar para as demais que tramalham com Swagger, a configuração é simples porem a escrita de documentação exige muita escrita tornando a manutenção árdua e suscetível a erro, oferece a opção de documentação em forma de comentários no código mas que se prova inviável pois polui visualmente o documento tornando difícil a compreensão e manutenção do mesmo.

    Exemplo de implementação Swagger UI Express

    yarn add swagger-ui-express
    const express = require('express');
    const app = express();
    const swaggerUi = require('swagger-ui-express');
    const swaggerDocument = require('./swagger.json');
    
    var options = {
      swaggerOptions: {
        validatorUrl: null
      }
    };
    
    app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, options));
    /**
     * @swagger
     * /:
     *     get:
     *          summary: Lista de produtos
     *          description: Lista de produtos usada para popular a grid e produtos
     *          responses:
     *              200:
     *                  description: lista
     *                  content:
     *                      application/json:
     *                          schema:
     *                              type: array
     *                              items:
     *                                  type: array
     *                                  items:
     *                                      type: object
     *                                      properties:
     *                                          id:
     *                                              type: string
     *                                              description: id do produto
     *                                              example: '0002321'
     *                                          categoria_id:
     *                                              type: string
     *                                              description: id da categoria
     *                                              example: '0254'
     *                                          ncm_id:
     *                                              type: string
     *                                              description: id do ncm
     *                                              example: '329'
     *                                          nome:
     *                                              type: string
     *                                              description: nome do produto
     *                                              example: Produto teste
     *                                          inativo?:
     *                                              type: number
     *                                              description: flag que indica se o produto esta ativo (1 ou null)
     *                                              example: 1
     */
    route.get('/', (req, res) => {
    	...
    })


    2.2 Express jsdoc swagger:

    Biblioteca que utiliza a 'swagger UI Express' citada anteriormente, segue a mesma premissa de documentação através de escrita de comentários no código e apresenta os mesmos problemas, poluição visual e dificuldade de manutenção.


    2.3 Routing Controller Openapi:

    Biblioteca que também utiliza a 'swagger UI Express', porem trás uma nova abordagem utilizando funções existentes no Typescript, usando decoradores podemos definir tipos de retornos, retornos múltiplos, casos onde ocorrem erros e exemplos de resposta, com o auxilio de outra biblioteca, 'class-validator-jsonschema', podemos definir schema de dados que nos ajuda a não repetir código e também oferecer um dicionário de dados.

    Segue a baixo um exemplo de implementação com a routing-controllers-openapi em um ambiente de teste. 

      2.3.1 Instalação:

      yarn add routing-controllers-openapi
      
      # Dependências
      yarn add class-validator-jsonschema # para criar dicionários de dados
      yarn add swagger-ui-express # para servir a documentação no swagger


      2.3.2 Configuração:

      // importação das bibliotecas
      import swagger from "swagger-ui-express";
      import { routingControllersToSpec } from "routing-controllers-openapi";
      import { validationMetadatasToSchemas } from "class-validator-jsonschema";
      
      // configuração do class-validator-jsonschema
      const schemas = validationMetadatasToSchemas({
        refPointerPrefix: "#/components/schemas/",
      });
      
      // recupera metadata das rotas
      const storage = getMetadataArgsStorage();
      
      // gera as especificações da documentação no padrão OpenAPI
      const spec = routingControllersToSpec(
        storage,
        {},
        {
          components: { schemas },
        },
      );
      
      app.use("/doc", swagger.serve, swagger.setup(spec)); // cria uma rota para servir a documentação
      


      2.3.3 Exemplo de implementação:

      import { IsNumber, IsString } from "class-validator";
      import { JSONSchema } from "class-validator-jsonschema";
      
      const example1 = {
        id: "001",
        nome: "Example",
        idade: 32,
      };
      
      const example2 = {
        id: "001",
        nome: "Example",
        idade: null,
      };
      
      @JSONSchema({ examples: [example1, example2] })
      export class User {
        @IsString()
        id!: string;
      
        @IsString()
        nome!: string;
      
        @IsNumber()
        idade?: number;
      }
      
      
      
      import { Body, Delete, Get, HttpCode, JsonController, Param, Post, Put } from "routing-controllers";
      import { OpenAPI, ResponseSchema } from "routing-controllers-openapi";
      import { ApplicationError } from "../error/ApplicationError";
      import { UserService } from '../services/user.service';
      import { User } from "../models/User.schema";
      
      @JsonController("/users")
      export class UserController {
        @Get("/")
        @ResponseSchema(User, { isArray: true })
        @ResponseSchema(ApplicationError, { statusCode: 400 })
        async list() {
          return await UserService.list()
        }
      
        @Get("/:userId")
        @ResponseSchema(User)
        @ResponseSchema(ApplicationError, { statusCode: 400 })
        async show(@Param("userId") userId: string): Promise<User> {
          return await UserService.getUserById(userId)
        }
      
        @HttpCode(201)
        @Post("/")
        @ResponseSchema(User)
        async store(@Body() user: User) {
      
          return await UserService.createUser(user);
        }
      
        @Put("/:userId")
        @ResponseSchema(User)
        async edit(@Param("userId") userId: string, @Body() user: User) {
          return user;
        }
      
        @Delete("/:userId")
        @HttpCode(204)
        @ResponseSchema("", { statusCode: 204 })
        @ResponseSchema(ApplicationError, { statusCode: 404 })
        async delete(@Param("userId") userId: string) {
          return await UserService.deleteUserById(userId)
        }
      }
      


      3. Conclusão

      Dessa forma a utilização da 'routing-controller-openapi' se mostrou mais eficaz dado que:

      • Simplicidade;
      • Facilidade de implementação;
      • Facilidade de manutenção; e,
      • Pouca poluição do código.
      • Uso de Typescript

      Desta forma, usando a melhor abordagem, sera possível documentar qualquer endpoint usando swagger com 2 pontos de complexidade anti o 1 ponto usado no postman.


      4. Referência

      [1] SWAGGER UI EXPRESS. Disponível em: https://www.npmjs.com/package/swagger-ui-express. Acesso em: 18 ago. 2021.


      [2] SWAGGER JSDOC. Disponível em: https://www.npmjs.com/package/swagger-jsdoc.  Acesso em: 18 ago. 2021.


      [3] How to Document an Express API with Swagger UI and JSDoc. 2020. Disponível em: https://dev.to/kabartolo/how-to-document-an-express-api-with-swagger-ui-and-jsdoc-50do.  Acesso em: 18 ago. 2021.


      [4] EXPRESS JSDOC SWAGGER. Disponível em: https://www.npmjs.com/package/express-jsdoc-swagger.  Acesso em: 18 ago. 2021.


      [5] ROUTING CONTROLLER OPENAPI. Disponível em: https://github.com/epiphone/routing-controllers-openapi.  Acesso em: 18 ago. 2021.