Identificação
- Módulo: 5 — Node.js, NestJS e APIs
- Duração: 2 horas
- Tipo: teoria aplicada e laboratório
- Entrega: contrato OpenAPI navegável da Knowledge API
- Laboratório:
../exemplos/aula-5.6/index.html
Introdução
Uma API não é apenas código no servidor. Ela é um acordo entre quem oferece uma função e quem precisa utilizá-la. O Angular precisa saber qual endereço chamar, quais dados enviar, quais respostas esperar e como interpretar uma falha.
Escrever essas informações somente em mensagens ou na memória da equipe cria dúvidas. OpenAPI é uma especificação para descrever APIs HTTP de forma estruturada. O documento gerado pode alimentar uma página navegável, ferramentas de teste, geradores de clientes e verificações automáticas.
Swagger não é sinônimo de OpenAPI. OpenAPI é a especificação. Swagger UI é uma
interface que lê um documento OpenAPI e apresenta operações, parâmetros e modelos.
No NestJS, o pacote @nestjs/swagger integra esses recursos à aplicação.
Nesta aula responderemos:
- documentação substitui validação?
- Swagger UI é a própria API?
- documentar uma resposta garante que o código a devolva?
- a interface pode ficar pública em produção?
- como descrever DTOs, parâmetros, exemplos, erros e autenticação?
- como evitar que código e documentação contem histórias diferentes?
Objetivos
Ao concluir a aula, você será capaz de:
- diferenciar OpenAPI, Swagger UI e documentação manual;
- instalar e configurar
@nestjs/swagger; - gerar um documento a partir da aplicação NestJS;
- organizar operações com títulos, descrições e etiquetas;
- documentar DTOs, parâmetros, consultas e respostas;
- fornecer exemplos úteis sem inserir dados sensíveis;
- representar erros padronizados;
- declarar autenticação sem publicar credenciais;
- exportar o documento em JSON;
- revisar divergências entre implementação e contrato.
Pré-requisitos
- aulas 5.1 a 5.5 concluídas;
- endpoints REST de tarefas;
- DTOs com validação;
- respostas de erro padronizadas;
- noção de prefixo global
/api.
1. O que é um contrato de API?
Contrato é a descrição observável da comunicação:
| Parte | Exemplo |
|---|---|
| método e caminho | POST /api/tasks |
| entrada | CreateTaskDto |
| resposta de sucesso | 201 com a tarefa criada |
| respostas de falha | 400, 409 e 500 |
| cabeçalhos | Content-Type, correlação e autenticação |
| significado | cria uma tarefa válida |
O contrato não descreve como o serviço salva a tarefa. Isso pertence à implementação.
2. OpenAPI, Swagger e NestJS
decorators + tipos + configuração NestJS
↓
documento OpenAPI
↙ ↘
Swagger UI JSON/YAML
- OpenAPI define a estrutura do documento;
@nestjs/swaggerexamina rotas e metadados;- Swagger UI apresenta o documento no navegador;
- JSON ou YAML pode ser usado por outras ferramentas.
3. Instalação
No terminal aberto na pasta da API:
npm install @nestjs/swagger
Esse comando instala a integração. Ele não cria endpoints de negócio nem valida DTOs.
4. Configuração inicial
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
const openApiConfig = new DocumentBuilder()
.setTitle('Knowledge API')
.setDescription('API de tarefas da plataforma Knowledge AI.')
.setVersion('1.0.0')
.addTag('tarefas', 'Operações de gerenciamento de tarefas.')
.build();
const documentFactory = () =>
SwaggerModule.createDocument(app, openApiConfig);
SwaggerModule.setup('docs', app, documentFactory, {
jsonDocumentUrl: 'docs/openapi.json',
customSiteTitle: 'Knowledge API | Documentação',
});
Com a API em http://localhost:3000:
- interface:
http://localhost:3000/docs; - documento:
http://localhost:3000/docs/openapi.json.
5. Ordem da inicialização
Registre prefixo, pipes e configuração antes de gerar o documento:
const app = await NestFactory.create(AppModule);
app.setGlobalPrefix('api');
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
configureOpenApi(app);
await app.listen(port);
O documento precisa refletir os caminhos realmente expostos.
6. O que o NestJS consegue descobrir?
O módulo reconhece rotas, métodos HTTP e tipos usados por decorators como:
@Body();@Param();@Query();@Controller();@Get(),@Post(),@Patch()e@Delete().
Nem toda intenção é inferida. Descrições, exemplos, respostas alternativas e regras de negócio precisam de metadados explícitos.
7. Etiquetas e operação
@ApiTags('tarefas')
@Controller('tasks')
export class TasksController {
@Get()
@ApiOperation({
summary: 'Listar tarefas',
description: 'Retorna tarefas filtradas por situação.',
})
list() {}
}
A etiqueta agrupa operações. O resumo deve começar com verbo e explicar a intenção.
8. DTO documentado
export class CreateTaskDto {
@ApiProperty({
description: 'Título visível da tarefa.',
example: 'Documentar a Knowledge API',
minLength: 3,
maxLength: 80,
})
@IsString()
@MinLength(3)
@MaxLength(80)
title!: string;
@ApiPropertyOptional({
description: 'Indica se a tarefa já foi concluída.',
example: false,
default: false,
})
@IsOptional()
@IsBoolean()
completed?: boolean;
}
@ApiProperty() documenta. class-validator valida em ambiente de execução. Uma
função não substitui a outra.
9. Classe de resposta
Não use o DTO de entrada para tudo. A saída pode possuir campos criados pelo servidor:
export class TaskResponseDto {
@ApiProperty({ example: 'task-001' })
id!: string;
@ApiProperty({ example: 'Documentar a Knowledge API' })
title!: string;
@ApiProperty({ example: false })
completed!: boolean;
@ApiProperty({ example: '2026-08-05T12:00:00.000Z' })
createdAt!: string;
}
10. Respostas de sucesso
@Post()
@ApiCreatedResponse({
description: 'Tarefa criada.',
type: TaskResponseDto,
})
create(@Body() input: CreateTaskDto): TaskResponseDto {
return this.tasksService.create(input);
}
Use o decorator específico quando ele tornar a intenção clara:
@ApiOkResponse()para200;@ApiCreatedResponse()para201;@ApiNoContentResponse()para204;@ApiNotFoundResponse()para404.
11. Listas e matrizes
@ApiOkResponse({ type: TaskResponseDto, isArray: true })
list(): TaskResponseDto[] {}
Sem isArray, a documentação poderá exibir um objeto quando o código devolve uma lista.
12. Parâmetro de rota
@Get(':id')
@ApiParam({
name: 'id',
description: 'Identificador da tarefa.',
example: 'task-001',
})
findOne(@Param('id') id: string) {}
O exemplo deve ser fictício, válido e coerente com o formato real.
13. Parâmetros de consulta
@ApiQuery({
name: 'completed',
required: false,
type: Boolean,
description: 'Filtra tarefas concluídas ou abertas.',
})
Também é possível usar uma classe de consulta. Isso concentra tipagem, validação e documentação em um contrato reaproveitável.
14. Erro padronizado
export class ApiErrorDto {
@ApiProperty({ example: 404 })
statusCode!: number;
@ApiProperty({ example: 'TASK_NOT_FOUND' })
code!: string;
@ApiProperty({ example: 'Tarefa não encontrada.' })
message!: string;
@ApiProperty({ example: 'req-a81f' })
correlationId!: string;
}
@ApiNotFoundResponse({
description: 'Tarefa inexistente.',
type: ApiErrorDto,
})
Documente os erros que o cliente precisa tratar. Não liste detalhes internos.
15. Exemplos seguros
Um exemplo bom:
- possui formato válido;
- explica o significado do campo;
- não contém nome, e-mail ou credencial real;
- não promete um valor que o servidor nunca devolve;
- ajuda o aluno a montar uma requisição.
Nunca use token real, senha, chave de API ou conteúdo privado na documentação.
16. Autenticação
const config = new DocumentBuilder()
.addBearerAuth()
.build();
@ApiBearerAuth()
@Controller('tasks')
export class TasksController {}
Isso descreve o mecanismo. Não autentica ninguém e não substitui guardas. A autenticação será implementada no Módulo 7.
17. A documentação deve ficar pública?
Depende do produto:
| Cenário | Decisão possível |
|---|---|
| API pública | documentação pública e versionada |
| API interna | autenticação, rede restrita ou acesso controlado |
| produção sensível | servir somente JSON controlado ou desabilitar a interface |
A decisão precisa considerar exposição de rotas, modelos internos e superfície de ataque.
18. Documento não é teste
Este decorator:
@ApiOkResponse({ type: TaskResponseDto })
não obriga o método a devolver aquele formato. A documentação pode mentir. Testes de contrato e revisão são necessários para reduzir divergência.
19. Versão da API e versão do documento
- versão do documento comunica evolução do contrato;
- versão do pacote comunica evolução do código distribuído;
- versão na URL, como
/v1, é uma estratégia de roteamento; - essas decisões se relacionam, mas não são idênticas.
Não altere um contrato incompatível silenciosamente.
20. Exportação para arquivo
O documento retornado por createDocument() é serializável. Ele pode ser salvo durante
uma tarefa controlada de compilação ou integração contínua:
const document = SwaggerModule.createDocument(app, config);
await writeFile(
'artifacts/openapi.json',
JSON.stringify(document, null, 2),
'utf8',
);
Evite escrever arquivos inesperadamente a cada requisição.
21. Plugin da CLI
O plug-in do Swagger pode adicionar metadados durante a compilação e reduzir repetição. Ele é opcional. Mesmo com o plug-in:
- mantenha validação em ambiente de execução;
- escreva descrições quando a intenção não for óbvia;
- forneça exemplos importantes;
- revise o documento gerado.
22. Roteiro de implementação
- instalar
@nestjs/swagger; - criar
configureOpenApi(app); - definir título, descrição e versão;
- registrar a interface e o documento JSON;
- etiquetar controladores;
- documentar operações, entradas e respostas;
- incluir erros padronizados;
- revisar exemplos e informações sensíveis;
- abrir a interface e inspecionar o JSON;
- registrar como a documentação será protegida em produção.
23. Laboratório guiado
Abra o explorador de contrato OpenAPI.
Etapa 1 — Escolha uma operação
Compare listagem, consulta por ID, criação e atualização.
Etapa 2 — Inspecione o contrato
Observe método, caminho, parâmetros, corpo e possíveis respostas.
Etapa 3 — Valide a documentação
Ative e desative metadados. O painel indica campos ausentes e riscos de divergência.
Etapa 4 — Veja o documento
Alterne entre a visão amigável e um fragmento OpenAPI equivalente.
24. Erros comuns
Confundir documentação com execução
Swagger UI envia requisições, mas a regra continua na API.
Documentar somente o caminho feliz
O cliente também precisa conhecer 400, 404, 409 e falhas seguras.
Reutilizar entidade em toda resposta
Entidades podem conter campos internos. Use contratos de saída explícitos.
Inserir segredo no exemplo
Documentação pode ser copiada, armazenada em cache e publicada.
Declarar tipo diferente do retorno real
Isso cria integração frágil. Corrija o código ou o contrato.
Publicar interface sem decisão
Disponibilidade da documentação deve ser uma escolha de segurança.
25. Exercícios
- documente
GET /api/healthcom resposta200; - documente
GET /api/tasks/:idcom200e404; - forneça exemplo seguro para
CreateTaskDto; - crie
ApiErrorDtocom correlação; - explique por que
@ApiProperty()não valida a entrada; - exporte um fragmento JSON e identifique
pathsecomponents.
26. Desafio individual
Adicione uma operação PATCH /api/tasks/:id ao contrato:
- parâmetro
id; - corpo parcial;
- resposta
200; - falhas
400e404; - exemplo de requisição;
- exemplo de resposta;
- nenhuma informação sensível.
27. Lista de verificação de conclusão
- Diferencio OpenAPI e Swagger UI.
- A documentação usa português claro.
- Operações possuem intenção compreensível.
- DTOs de entrada e saída estão separados.
- Listas são documentadas como listas.
- Parâmetros e consultas possuem exemplos.
- Erros importantes estão representados.
- Nenhum segredo aparece no documento.
- Sei que documentação não substitui validação ou testes.
- O JSON do contrato pode ser obtido de forma controlada.
28. Rubrica da entrega
| Critério | Pontos |
|---|---|
| Configuração do documento | 20 |
| Operações e organização | 20 |
| DTOs e modelos de resposta | 20 |
| Erros e exemplos | 20 |
| Segurança e coerência | 20 |
| Total | 100 |
29. Resumo
- OpenAPI descreve contratos HTTP de forma estruturada;
- Swagger UI apresenta o documento no navegador;
@nestjs/swaggerintegra rotas e metadados do NestJS;- documentação, validação e teste possuem responsabilidades diferentes;
- exemplos devem ser úteis, fictícios e seguros;
- contrato e implementação precisam ser revisados em conjunto.
Próxima aula
Na Aula 5.7, adicionaremos registros estruturados, interceptadores de observação e uma suíte de testes unitários e de integração.