Swagger: melhores abordagens para documentação
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 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. 3. Desenvolvimento 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 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. 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. Dessa forma a utilização da 'routing-controller-openapi' se mostrou mais eficaz dado que: 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. [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.Data:
Data de elaboração
18/08/2021
Autores:
Responsável pelo estudo
Equipe do estudo
Esquadrão Suicida
Alvo
Swagger
Origem
1.Implementação: casos de novas implementações
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)
Observações
Não possui.
2.Glossário
1. Introdução
2. Desenvolvimento
3.2.1 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) => {
...
})
3.2.2 Express jsdoc swagger:3.2.3 Routing Controller Openapi:
3.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
3.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
3.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)
}
}
4.3. Conclusão
5.4. Referência