DEV Community

Cover image for Adeus, Swagger UI ? Uma alternativa elegante com Redoc
Danilo O. Pinheiro, dopme.io
Danilo O. Pinheiro, dopme.io

Posted on

Adeus, Swagger UI ? Uma alternativa elegante com Redoc

Neste artigo, vamos explorar como criar uma API RESTful completa em .NET 8 usando Minimal APIs, implementando um CRUD (Create, Read, Update, Delete) completo para cadastro de pessoas. Além disso, vamos integrar OpenAPI/Swagger para documentação automática e Redoc para uma interface de documentação interativa e elegante.

O projeto demonstra as melhores práticas modernas de desenvolvimento .NET, incluindo:

  • Minimal APIs para endpoints limpos e diretos
  • Validação de dados com Data Annotations
  • Documentação automática com OpenAPI 3.0
  • Interface de documentação com Redoc
  • Arquitetura em camadas com serviços e modelos separados

🛠️ Tecnologias Utilizadas

  • .NET 8.0 - Framework moderno e de alto desempenho
  • Minimal APIs - Abordagem simplificada para criar APIs REST
  • Swashbuckle.AspNetCore - Geração automática de documentação OpenAPI/Swagger
  • Redoc - Interface de documentação interativa e elegante
  • Data Annotations - Validação de dados nativa do .NET

📁 Estrutura do Projeto

NR.Api/
├── Models/
│   ├── Pessoa.cs                  # Modelo de domínio
│   ├── CriarPessoaRequest.cs      # DTO para criação
│   └── AtualizarPessoaRequest.cs  # DTO para atualização
├── Services/
│   ├── IPessoaService.cs          # Interface do serviço
│   └── PessoaService.cs           # Implementação do serviço (em memória)
├── Properties/
│   └── launchSettings.json        # Configurações de execução
├── wwwroot/
│   ├── index.html                 # Página inicial
│   └── redoc.html                 # Interface Redoc
├── Program.cs                     # Configuração e endpoints
└── NR.Api.csproj                  # Arquivo do projeto
Enter fullscreen mode Exit fullscreen mode

🚀 Como Executar o Projeto

Pré-requisitos

  • .NET 8 SDK instalado
  • Visual Studio 2022, VS Code ou Rider (opcional)

Passos para Executar

  1. Clone ou navegue até o diretório do projeto
cd NR.Api
Enter fullscreen mode Exit fullscreen mode
  1. Restaura as dependências
dotnet restore
Enter fullscreen mode Exit fullscreen mode
  1. Execute a aplicação
dotnet run
Enter fullscreen mode Exit fullscreen mode
  1. Acesse a documentação

📚 Modelos de Dados

Pessoa (Modelo de Domínio)

public class Pessoa
{
    public Guid Id { get; set; }
    public string Nome { get; set; } = string.Empty;
    public string Email { get; set; } = string.Empty;
    public string Telefone { get; set; } = string.Empty;
    public DateTime DataNascimento { get; set; }
    public string? Endereco { get; set; }
    public DateTime DataCriacao { get; set; }
    public DateTime? DataAtualizacao { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

CriarPessoaRequest (DTO de Criação)

public class CriarPessoaRequest
{
    [Required(ErrorMessage = "O nome é obrigatório")]
    [StringLength(200, MinimumLength = 2)]
    public string Nome { get; set; } = string.Empty;

    [Required(ErrorMessage = "O email é obrigatório")]
    [EmailAddress(ErrorMessage = "O email deve ser válido")]
    public string Email { get; set; } = string.Empty;

    [Required(ErrorMessage = "O telefone é obrigatório")]
    [StringLength(20, MinimumLength = 10)]
    public string Telefone { get; set; } = string.Empty;

    [Required(ErrorMessage = "A data de nascimento é obrigatória")]
    public DateTime DataNascimento { get; set; }

    [StringLength(500)]
    public string? Endereco { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

AtualizarPessoaRequest (DTO de Atualização)

Similar ao CriarPessoaRequest, usado para atualização de dados.

🔌 Endpoints da API

1. Health Check

GET /health

Retorna o status de saúde da aplicação.

Resposta:

{
  "status": "healthy",
  "timestamp": "2024-01-09T10:30:00Z",
  "version": "1.0.0"
}
Enter fullscreen mode Exit fullscreen mode

2. Listar Todas as Pessoas

GET /api/pessoas

Retorna uma lista com todas as pessoas cadastradas.

Resposta (200 OK):

[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "nome": "João Silva",
    "email": "joao.silva@email.com",
    "telefone": "(11) 98765-4321",
    "dataNascimento": "1990-05-15T00:00:00Z",
    "endereco": "Rua Exemplo, 123",
    "dataCriacao": "2024-01-09T10:00:00Z",
    "dataAtualizacao": null
  }
]
Enter fullscreen mode Exit fullscreen mode

3. Obter Pessoa por ID

GET /api/pessoas/{id}

Retorna os dados de uma pessoa específica.

Parâmetros:

  • id (Guid): ID único da pessoa

Resposta (200 OK):

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "nome": "João Silva",
  "email": "joao.silva@email.com",
  "telefone": "(11) 98765-4321",
  "dataNascimento": "1990-05-15T00:00:00Z",
  "endereco": "Rua Exemplo, 123",
  "dataCriacao": "2024-01-09T10:00:00Z",
  "dataAtualizacao": null
}
Enter fullscreen mode Exit fullscreen mode

Resposta (404 Not Found):

{
  "message": "Pessoa com ID {id} não encontrada"
}
Enter fullscreen mode Exit fullscreen mode

4. Criar Nova Pessoa

POST /api/pessoas

Cria uma nova pessoa no sistema.

Body (JSON):

{
  "nome": "Maria Santos",
  "email": "maria.santos@email.com",
  "telefone": "(11) 91234-5678",
  "dataNascimento": "1985-08-20",
  "endereco": "Avenida Principal, 456"
}
Enter fullscreen mode Exit fullscreen mode

Resposta (201 Created):

{
  "id": "660e8400-e29b-41d4-a716-446655440001",
  "nome": "Maria Santos",
  "email": "maria.santos@email.com",
  "telefone": "(11) 91234-5678",
  "dataNascimento": "1985-08-20T00:00:00Z",
  "endereco": "Avenida Principal, 456",
  "dataCriacao": "2024-01-09T10:15:00Z",
  "dataAtualizacao": null
}
Enter fullscreen mode Exit fullscreen mode

Resposta (400 Bad Request):

{
  "errors": [
    "O nome é obrigatório",
    "O email deve ser válido"
  ]
}
Enter fullscreen mode Exit fullscreen mode

5. Atualizar Pessoa

PUT /api/pessoas/{id}

Atualiza os dados de uma pessoa existente.

Parâmetros:

  • id (Guid): ID único da pessoa

Body (JSON):

{
  "nome": "Maria Santos Silva",
  "email": "maria.silva@email.com",
  "telefone": "(11) 91234-5678",
  "dataNascimento": "1985-08-20",
  "endereco": "Avenida Principal, 456 - Apto 101"
}
Enter fullscreen mode Exit fullscreen mode

Resposta (200 OK):

{
  "id": "660e8400-e29b-41d4-a716-446655440001",
  "nome": "Maria Santos Silva",
  "email": "maria.silva@email.com",
  "telefone": "(11) 91234-5678",
  "dataNascimento": "1985-08-20T00:00:00Z",
  "endereco": "Avenida Principal, 456 - Apto 101",
  "dataCriacao": "2024-01-09T10:15:00Z",
  "dataAtualizacao": "2024-01-09T10:20:00Z"
}
Enter fullscreen mode Exit fullscreen mode

6. Deletar Pessoa

DELETE /api/pessoas/{id}

Remove uma pessoa do sistema.

Parâmetros:

  • id (Guid): ID único da pessoa

Resposta (204 No Content): Sem corpo de resposta

Resposta (404 Not Found):

{
  "message": "Pessoa com ID {id} não encontrada"
}
Enter fullscreen mode Exit fullscreen mode

💻 Implementação do Serviço

O serviço PessoaService utiliza um dicionário em memória para armazenar os dados. Em uma aplicação de produção, você substituiria isso por um banco de dados (SQL Server, PostgreSQL, MongoDB, etc.).

public class PessoaService : IPessoaService
{
    private readonly Dictionary<Guid, Pessoa> _pessoas = new();
    private readonly object _lock = new();

    public Task<Pessoa> CriarAsync(CriarPessoaRequest request)
    {
        lock (_lock)
        {
            var pessoa = new Pessoa
            {
                Id = Guid.NewGuid(),
                Nome = request.Nome,
                Email = request.Email,
                Telefone = request.Telefone,
                DataNascimento = request.DataNascimento,
                Endereco = request.Endereco,
                DataCriacao = DateTime.UtcNow
            };

            _pessoas[pessoa.Id] = pessoa;
            return Task.FromResult(pessoa);
        }
    }

    // ... outros métodos
}
Enter fullscreen mode Exit fullscreen mode

✅ Validação de Dados

O projeto utiliza Data Annotations para validação de dados. As validações incluem:

  • Required: Campos obrigatórios
  • EmailAddress: Validação de formato de email
  • StringLength: Limitação de tamanho de strings
  • MinimumLength: Tamanho mínimo de strings

Exemplo de validação no endpoint:

var validationResults = new List<ValidationResult>();
var validationContext = new ValidationContext(request);

if (!Validator.TryValidateObject(request, validationContext, validationResults, true))
{
    return Results.BadRequest(new { errors = validationResults.Select(v => v.ErrorMessage) });
}
Enter fullscreen mode Exit fullscreen mode

🧪 Testando a API

Usando cURL

Listar pessoas:

curl -X GET http://localhost:5059/api/pessoas
Enter fullscreen mode Exit fullscreen mode

Criar pessoa:

curl -X POST http://localhost:5059/api/pessoas \
  -H "Content-Type: application/json" \
  -d '{
    "nome": "João Silva",
    "email": "joao.silva@email.com",
    "telefone": "(11) 98765-4321",
    "dataNascimento": "1990-05-15",
    "endereco": "Rua Exemplo, 123"
  }'
Enter fullscreen mode Exit fullscreen mode

Atualizar pessoa:

curl -X PUT http://localhost:5059/api/pessoas/{id} \
  -H "Content-Type: application/json" \
  -d '{
    "nome": "João Silva Santos",
    "email": "joao.santos@email.com",
    "telefone": "(11) 98765-4321",
    "dataNascimento": "1990-05-15",
    "endereco": "Rua Exemplo, 123"
  }'
Enter fullscreen mode Exit fullscreen mode

Deletar pessoa:

curl -X DELETE http://localhost:5059/api/pessoas/{id}
Enter fullscreen mode Exit fullscreen mode

Usando Postman ou Insomnia

Importe a especificação OpenAPI disponível em /swagger/v1/swagger.json no Postman ou Insomnia para ter acesso a todos os endpoints pré-configurados.

🎨 Documentação com OpenAPI e Redoc

OpenAPI/Swagger

O projeto utiliza Swashbuckle.AspNetCore para gerar automaticamente a documentação OpenAPI 3.0. A especificação OpenAPI está disponível em:

Gerando HTML Estático com Redocly CLI para Produção

Para ambiente de produção, é recomendado gerar uma versão estática da documentação usando o Redocly CLI. Isso oferece melhor performance e pode ser servido por qualquer servidor web estático.

Passo A — Instalar Redocly CLI (Node)

Primeiro, instale o Redocly CLI globalmente usando npm:

npm install -g @redocly/cli
Enter fullscreen mode Exit fullscreen mode

Nota: É necessário ter o Node.js instalado em sua máquina. Você pode baixá-lo em nodejs.org.

Passo B — Gerar o OpenAPI JSON localmente

Com a API rodando, baixe o arquivo JSON da especificação OpenAPI:

curl http://localhost:5059/swagger/v1/swagger.json -o openapi.json
Enter fullscreen mode Exit fullscreen mode

Ou, no Windows PowerShell:

Invoke-WebRequest -Uri http://localhost:5059/swagger/v1/swagger.json -OutFile openapi.json
Enter fullscreen mode Exit fullscreen mode

Passo C — Gerar o HTML do Redoc

Execute o comando para gerar o HTML estático:

redocly build-docs openapi.json
Enter fullscreen mode Exit fullscreen mode

Isso cria um arquivo redoc-static.html no diretório atual.

Passo D — Colocar o HTML no wwwroot

Agora você pode mover o arquivo gerado para o diretório wwwroot e servi-lo diretamente:

mkdir -p wwwroot
mv redoc-static.html wwwroot/index.html
Enter fullscreen mode Exit fullscreen mode

Ou, no Windows PowerShell:

New-Item -ItemType Directory -Force -Path wwwroot
Move-Item -Path redoc-static.html -Destination wwwroot/index.html
Enter fullscreen mode Exit fullscreen mode

Agora abra http://localhost:5059/index.html para ver a documentação estática.

Vantagens do Redocly CLI

  • Configuração personalizada: Diferentes opções de configuração e temas
  • Lint e validação: Valida a especificação OpenAPI antes de gerar
  • Bundle da spec: Consolida referências externas em um único arquivo
  • Builds automatizados: Integra facilmente em pipelines de CI/CD
  • Deploy estático: Pode ser servido por qualquer servidor web estático (Nginx, Azure Static Web Apps, GitHub Pages, etc.)
  • Melhor performance: HTML estático carrega mais rápido que versões dinâmicas

Exemplo de Configuração Avançada

Você também pode criar um arquivo de configuração redocly.yaml para personalizar a geração:

apis:
  main:
    root: openapi.json
theme:
  colors:
    primary:
      main: '#32329f'
  typography:
    fontSize: '14px'
Enter fullscreen mode Exit fullscreen mode

E então usar:

redocly build-docs openapi.json --config redocly.yaml
Enter fullscreen mode Exit fullscreen mode

🔒 Próximos Passos e Melhorias

Para tornar esta API pronta para produção, considere:

  1. Persistência de Dados: Substituir o dicionário em memória por um banco de dados (Entity Framework Core, Dapper, etc.)
  2. Autenticação e Autorização: Implementar JWT, OAuth 2.0 ou Identity
  3. Logging: Adicionar logging estruturado (Serilog, NLog)
  4. Tratamento de Erros Global: Middleware para tratamento centralizado de exceções
  5. Rate Limiting: Limitar requisições por IP/usuário
  6. Caching: Implementar cache para consultas frequentes
  7. Versionamento de API: Suporte para múltiplas versões da API
  8. Testes Automatizados: Unit tests e integration tests
  9. CI/CD: Pipeline de build e deploy automatizado
  10. Monitoramento: Application Insights, Prometheus, etc.

📖 Conclusão

Este projeto demonstra como criar uma API RESTful completa e moderna usando .NET 8 com Minimal APIs. Através do uso de OpenAPI e Redoc, conseguimos gerar documentação automática e interativa, facilitando o desenvolvimento e a integração com outros sistemas.

As Minimal APIs do .NET 8 oferecem uma abordagem simplificada e performática para criar APIs REST, enquanto o OpenAPI e Redoc garantem uma experiência de documentação profissional e acessível.

🤝 Conecte-se Comigo

Se você trabalha com .NET moderno e quer dominar arquitetura, C#, DevOps ou interoperabilidade, vamos conversar:

💼 LinkedIn

💻 DEV Community

✍️ Medium

📰 Substack

📧 Email

⁷ Agora, pois, seja o temor do Senhor convosco; guardai-o, e fazei-o; porque não há no Senhor nosso Deus iniquidade nem acepção de pessoas, nem aceitação de suborno. 2 Crônicas 19:7

Top comments (0)