# Aula 5.6 — OpenAPI e documentação

## 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`](../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:

1. diferenciar OpenAPI, Swagger UI e documentação manual;
2. instalar e configurar `@nestjs/swagger`;
3. gerar um documento a partir da aplicação NestJS;
4. organizar operações com títulos, descrições e etiquetas;
5. documentar DTOs, parâmetros, consultas e respostas;
6. fornecer exemplos úteis sem inserir dados sensíveis;
7. representar erros padronizados;
8. declarar autenticação sem publicar credenciais;
9. exportar o documento em JSON;
10. 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

```text
decorators + tipos + configuração NestJS
                    ↓
          documento OpenAPI
             ↙             ↘
      Swagger UI          JSON/YAML
```

- OpenAPI define a estrutura do documento;
- `@nestjs/swagger` examina 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:

```powershell
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

```ts
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:

```ts
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

```ts
@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

```ts
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:

```ts
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

```ts
@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()` para `200`;
- `@ApiCreatedResponse()` para `201`;
- `@ApiNoContentResponse()` para `204`;
- `@ApiNotFoundResponse()` para `404`.

## 11. Listas e matrizes

```ts
@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

```ts
@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

```ts
@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

```ts
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;
}
```

```ts
@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

```ts
const config = new DocumentBuilder()
  .addBearerAuth()
  .build();
```

```ts
@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:

```ts
@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:

```ts
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

1. instalar `@nestjs/swagger`;
2. criar `configureOpenApi(app)`;
3. definir título, descrição e versão;
4. registrar a interface e o documento JSON;
5. etiquetar controladores;
6. documentar operações, entradas e respostas;
7. incluir erros padronizados;
8. revisar exemplos e informações sensíveis;
9. abrir a interface e inspecionar o JSON;
10. registrar como a documentação será protegida em produção.

## 23. Laboratório guiado

Abra o [explorador de contrato OpenAPI](../exemplos/aula-5.6/index.html).

### 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

1. documente `GET /api/health` com resposta `200`;
2. documente `GET /api/tasks/:id` com `200` e `404`;
3. forneça exemplo seguro para `CreateTaskDto`;
4. crie `ApiErrorDto` com correlação;
5. explique por que `@ApiProperty()` não valida a entrada;
6. exporte um fragmento JSON e identifique `paths` e `components`.

## 26. Desafio individual

Adicione uma operação `PATCH /api/tasks/:id` ao contrato:

- parâmetro `id`;
- corpo parcial;
- resposta `200`;
- falhas `400` e `404`;
- 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/swagger` integra 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.

## Fontes oficiais

- [NestJS — introdução ao OpenAPI](https://docs.nestjs.com/openapi/introduction)
- [NestJS — tipos e parâmetros](https://docs.nestjs.com/openapi/types-and-parameters)
- [NestJS — operações](https://docs.nestjs.com/openapi/operations)
- [NestJS — segurança no OpenAPI](https://docs.nestjs.com/openapi/security)
- [NestJS — plugin da CLI](https://docs.nestjs.com/openapi/cli-plugin)
