NestJS e Swagger: Automatize a geração de documentação para sua API
Desenvolver uma API é apenas o primeiro passo. Para que essa API seja utilizada por outros desenvolvedores, é fundamental que ela seja bem documentada. É necessário especificar de alguma forma, como a API funciona, quais são seus recursos e como consumi-los. Nesse contexto, a especificação OpenAPI oferece um padrão para descrever APIs, facilitando seu entendimento e o consumo.
OpenAPI Specification (formerly Swagger Specification) is an API description format for REST APIs. An OpenAPI file allows you to describe your entire API, including:
Available endpoints (/users
) and operations on each endpoint (GET /users
,POST /users
)
Operation parameters Input and output for each operation
Authentication methods
Contact information, license, terms of use, and other information.
API specifications can be written in YAML or JSON. The format is easy to learn and readable to both humans and machines. The complete OpenAPI Specification can be found on GitHub: OpenAPI 3.0 Specification
https://swagger.io/docs/specification/v3_0/about/
Ao utilizar a especificação da OpenAPI, conhecida antigamente como especificação Swagger, é possível gerar uma documentação interativa que inclui informações detalhadas sobre os endpoints, os métodos HTTP suportados, os parâmetros de requisição e resposta, além de exemplos de uso. Essa documentação pode ser acessada através de uma interface visual, como o Swagger UI, que permite testar a API diretamente no navegador conforme a imagem abaixo ilustra. Também é possível gerar a documentação em um arquivo YAML ou JSON.
Uma das formas de gerarmos essa documentação para uma API, é criando manualmente um arquivo JSON ou YAML. Contudo, os frameworks geralmente oferecem recursos que facilitam esse processo. No caso do NestJS, por exemplo, é possível instalar pacotes específicos e utilizar decorators para efetuar a documentação. Inclusive, este é o tema deste texto.
Criando uma API com NestJS
Para iniciar, o pequeno script abaixo gera uma aplicação NestJS:
# Versões:
node -v
# v22.11.0
nest -v
# 10.4.7
# Criando o projeto
nest new \
--skip-git \
-p npm \
-l typescript \
--strict \
exemplo-swagger
# Entrando no diretório do novo projeto
cd exemplo-swagger/
# Executando o projeto
npm run start:dev
# Testando o projeto com cURL
curl -i localhost:3000
#
# Resultado:
#
# HTTP/1.1 200 OK
# X-Powered-By: Express
# Content-Type: text/html; charset=utf-8
# Content-Length: 12
#
# Hello World!
Configurando o Swagger
Após criar a aplicação, é necessário instalar alguns pacotes conforme o seguinte script:
npm install --save @nestjs/swagger
# Também instalei os pacotes para
# ajudar na validação de dados. Se
# quiser saber mais sobre esse assunto:
# https://consolelog.com.br/validando-dados-api-class-validator-class-transformer-nestjs
npm i --save class-validator class-transformer
Uma vez instalado os pacotes acima, é necessário configurar o Swagger no módulo principal da aplicação, importando o SwaggerModule
e DocumentBuilder
conforme a seguir:
Com apenas essa pequena configuração, você já pode visualizar a documentação Swagger gerada. Para isso, execute a aplicação com o comando npm run start:dev
e acesse o endereço http://localhost:3000/api
no navegador.
Como a aplicação contém um único endpoint (GET /
), somente ele foi mapeado na documentação, conforme a imagem acima ilustra. Continuando os estudos, vamos aprender a detalhar melhor este único endpoint.
Como documentar um endpoint com os decorators do swagger
Através de uma série de decorators, é possível por exemplo, descrever um método, relatar quais são os possíveis retornos, quais são as query strings presentes, entre outros.
No código abaixo foi utilizado o ApiOperation
e ApiResponse
para descrever o endpoint GET /
e documentar os possíveis retornos.
Após aplicar os decorators, os detalhes são refletidos na documentação:
A seguir, será abordado cenários mais próximos ao cotidiano, como a documentação de rotas que envolvem, query string, parâmetros de URL, corpo (body) e cabeçalhos de requisição e resposta.
Como documentar query string, corpo de resposta e um cabeçalho de requisição e resposta no swagger
No exemplo a seguir, é apresentado o endpoint GET /usuarios
. Para fins de teste, esta rota exige o cabeçalho x-request-teste
. Além disso, inclui a query string opcional nome
.
Como esta rota retorna uma lista de usuários, foi necessário criar a classe UsuarioModel
e documentar os campos conforme abaixo.
No método find
, dentro de UsuariosController
, foram adicionados alguns decorators para documentar o endpoint:
Observe no resultado que cada decorator representa um trecho na documentação. Por exemplo, o ApiHeader
descreve um cabeçalho que é esperado na requisição, já o ApiResponse
detalha como será a resposta do endpoint para um determinado http status code:
Como incluir parâmetros de URL no Swagger
Outro cenário comum, é o uso de parâmetros na URL. Por exemplo, GET /usuarios/:id
. Neste caso podemos utilizar o decorator ApiParam
para descrever os parâmetros:
Como documentar o corpo de requisição (request body)
Normalmente utilizando os método POST, PUT ou PATCH, é comum ter um corpo de requisição, normalmente um JSON. Para documentar esse request body, podemos criar uma classe e aplicar tanto os decorators de validação, que já foram abordados por aqui, quanto os do Swagger. Observe no código a seguir:
Já no método dentro do controller, a documentação é muito semelhante aos outros endpoints apresentados anteriormente. Basta especificar o tipo da classe recebida como parâmetro do método e incluir o decorator@Body
do NestJS:
Como documentar o token de acesso
É extremamente comum que haja um processo de autenticação e autorização em APIs. A mecânica básica é através da utilização de tokens de acesso. Após o usuário se autenticar (por exemplo, fornecendo um nome de usuário e senha), a API gera um token, que é enviado ao usuário.
Em todas as requisições subsequentes, o usuário inclui o token de acesso no cabeçalho da requisição. A API verifica a validade do token e, se estiver válido, autoriza o usuário a realizar a ação solicitada.
Para simular esse cenário no projeto de estudo deste texto, foi criado uma classe chamada AuthGuard
, que é responsável por validar um valor fixo no cabeçalho de requisição authentication
.
Essa classe foi registrada no provide APP_GUARD
. Isso significa que antes de executar o método de cada rota, a classe AuthGuard
é executada para validar se o token de acesso está presente e é válido.
Agora que todos os endpoints estão protegidos, para documentar isto no swagger é necessário chamar o método .addBearerAuth()
durante a configuração do DocumentBuilder
do Swagger:
Para indicar na documentação do Swagger quais endpoints estão protegidos, basta adicionar o decorator @ApiBearerAuth()
ao método ou ao controller. Quando aplicado no controller, todos os endpoints contidos nele serão documentados com o filtro de autenticação.
Após essa configuração, ao executar o projeto e acessar a documentação no endereço http://localhost:3000/api
, será exibido o botão "Authorize" no canto superior direito, além de um ícone de cadeado ao lado de cada endpoint protegido. Ao clicar em "Authorize", você poderá inserir o token de acesso, permitindo consumir os endpoints diretamente pela interface visual no navegador.
Organizando os decorators do swagger
O uso de decorators para documentação, como os do Swagger, em alguns casos pode tornar o código menos legível devido à alta densidade. Uma possível solução é agrupar esses decorators em um arquivo separado, criando um único decorator consolidado. Assim, basta importar esse agrupador no código. Confira o exemplo abaixo:
Após agrupar os decorators no decorator ApiUsuariosPost
, conforme o código acima, basta importar o @ApiUsuariosPost()
e adicioná-lo no método desejado:
Gerando o JSON ou YAML do Swagger
Para gerar o Swagger no formato JSON ou YAML, basta incluir o seguinte trecho no arquivo main.ts:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import {
DocumentBuilder,
SwaggerModule,
} from '@nestjs/swagger';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const config = new DocumentBuilder()
.setTitle('API de Estudo')
.setDescription('Documentação - consolelog.com.br')
.setVersion('1.0')
.addBearerAuth()
.build();
const documentFactory = () =>
SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, documentFactory);
// ###################################################
SwaggerModule.setup('swagger', app, documentFactory, {
jsonDocumentUrl: 'swagger/json',
yamlDocumentUrl: 'swagger/yaml',
});
// ###################################################
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
Feito isto, após executar o projeto é possível acessar as rotas /swagger/json
ou /swagger/yaml
para obter a documentação no formato desejado.
Considerações
O uso do Swagger na documentação de APIs proporciona detalhes de forma clara, interativa e facilmente acessível para os desenvolvedores. Ele simplifica o entendimento e a comunicação sobre os endpoints disponíveis, seus parâmetros, retornos e requisitos de autenticação. Além disso, a integração do NestJS com o Swagger, por meio de decorators, torna o processo de documentação bem simples.
Abaixo deixo alguns links interessantes sobre o assunto: