"Documentação de API é o contrato entre backend e frontend. OpenAPI torna isso automático, sempre atualizado e testável." — #30DiasJava Developer Experience Notes

🎯 Objetivo do Day 21

Para facilitar o desenvolvimento e integração com a API, o Day 21 do #30DiasJava implementou documentação automática de APIs usando OpenAPI 3.0 e Swagger UI, com integração JWT, UI interativa e geração automática de especificações.

🛠️ O que foi implementado

✅ OpenAPI 3.0 Specification

  • Automatic generation: Geração automática de especificação OpenAPI a partir de anotações
  • SpringDoc OpenAPI: Integração com Spring Boot via SpringDoc
  • API info: Informações da API (título, descrição, versão)
  • Security schemes: Configuração de esquemas de segurança (JWT Bearer)

✅ Swagger UI

  • Interactive UI: Interface web interativa para testar APIs
  • Try it out: Testar endpoints diretamente do navegador
  • Request/Response examples: Exemplos de requests e responses
  • Authentication: Suporte para autenticação JWT na UI

✅ API Documentation

  • Controller annotations: Documentação de controllers com @Tag
  • Operation annotations: Documentação de operações com @Operation
  • Parameter annotations: Documentação de parâmetros com @Parameter
  • Response annotations: Documentação de responses com @ApiResponse

✅ Security Integration

  • JWT Bearer token: Configuração de autenticação JWT na documentação
  • Security requirements: Requisitos de segurança por endpoint
  • Token input: Campo para inserir token JWT na UI

📊 Arquitetura

┌─────────────────────────────────────────────────────────┐
│              Spring Boot Application                     │
│  ┌──────────────────────────────────────────────────┐  │
│  │  Controllers com anotações OpenAPI               │  │
│  │  @RestController, @Operation, @Tag                │  │
│  └──────────────────────────────────────────────────┘  │
└──────────────────────┬──────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────┐
│              SpringDoc OpenAPI                            │
│  ┌──────────────────────────────────────────────────┐  │
│  │  1. Scan controllers e anotações                 │  │
│  │  2. Gerar OpenAPI spec (JSON/YAML)                │  │
│  │  3. Expor Swagger UI                              │  │
│  └──────────────────────────────────────────────────┘  │
└──────────────────────┬──────────────────────────────────┘
                       │
        ┌──────────────┼──────────────┐
        ▼              ▼              ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│  /swagger-ui │ │ /v3/api-docs │ │  OpenAPI     │
│  (UI)        │ │  (JSON)      │ │  Spec        │
└──────────────┘ └──────────────┘ └──────────────┘

💻 Implementação

Dependências (pom.xml)

<!-- OpenAPI -->
<dependency>
  <groupId>org.springdoc</groupId>
  <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
  <version>2.6.0</version>
</dependency>

OpenApiConfig

@Configuration
public class OpenApiConfig {

    @Bean
    public OpenAPI api() {
        final String schemeName = "bearerAuth";
        return new OpenAPI()
            .info(new Info()
                .title("Desafio das Águias API")
                .description("Spring Boot + JWT + Missions")
                .version("0.1.0"))
            .addSecurityItem(new SecurityRequirement().addList(schemeName))
            .components(new Components()
                .addSecuritySchemes(schemeName, new SecurityScheme()
                    .name(schemeName)
                    .type(SecurityScheme.Type.HTTP)
                    .scheme("bearer")
                    .bearerFormat("JWT")));
    }
}

Controller Documentation Example

@RestController
@RequestMapping("/api/familias")
@Tag(name = "Familias", description = "API para gerenciamento de famílias")
public class FamiliaController {

    @Autowired
    private FamiliaService familiaService;

    @GetMapping
    @Operation(
        summary = "Listar famílias",
        description = "Retorna lista paginada de famílias com suporte a busca e ordenação"
    )
    @ApiResponses(value = {
        @ApiResponse(
            responseCode = "200",
            description = "Lista de famílias retornada com sucesso",
            content = @Content(
                mediaType = "application/json",
                schema = @Schema(implementation = FamiliaDTO.class)
            )
        ),
        @ApiResponse(
            responseCode = "401",
            description = "Não autenticado"
        ),
        @ApiResponse(
            responseCode = "403",
            description = "Não autorizado"
        )
    })
    public ResponseEntity<Page<FamiliaDTO>> listarFamilias(
            @Parameter(description = "Termo de busca") 
            @RequestParam(required = false) String busca,
            @Parameter(description = "Paginação") 
            Pageable pageable) {
        Page<FamiliaDTO> familias = familiaService.listar(busca, pageable);
        return ResponseEntity.ok(familias);
    }

    @PostMapping
    @Operation(
        summary = "Criar família",
        description = "Cria uma nova família no sistema"
    )
    @ApiResponses(value = {
        @ApiResponse(
            responseCode = "201",
            description = "Família criada com sucesso"
        ),
        @ApiResponse(
            responseCode = "400",
            description = "Dados inválidos"
        )
    })
    @PreAuthorize("hasRole('USER')")
    public ResponseEntity<FamiliaDTO> criarFamilia(
            @Parameter(description = "Dados da família")
            @Valid @RequestBody CriarFamiliaRequest request) {
        FamiliaDTO familia = familiaService.criar(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(familia);
    }
}

Configuration (application.yml)

springdoc:
  api-docs:
    enabled: true
    path: /v3/api-docs
  swagger-ui:
    enabled: true
    path: /swagger-ui
    operations-sorter: method
    tags-sorter: alpha
    try-it-out-enabled: true
  show-actuator: false

📈 Uso da Documentação

1. Acessar Swagger UI

http://localhost:8080/swagger-ui

A interface Swagger UI permite:

  • Explorar endpoints: Ver todos os endpoints disponíveis
  • Ver schemas: Ver modelos de dados (DTOs, Entities)
  • Testar endpoints: Fazer requests diretamente da UI
  • Autenticar: Inserir token JWT para testar endpoints protegidos

2. Obter OpenAPI Specification

# JSON format
curl http://localhost:8080/v3/api-docs

# YAML format (se configurado)
curl http://localhost:8080/v3/api-docs.yaml

3. Exemplo de OpenAPI Spec Gerado

{
  "openapi": "3.0.1",
  "info": {
    "title": "Desafio das Águias API",
    "description": "Spring Boot + JWT + Missions",
    "version": "0.1.0"
  },
  "servers": [
    {
      "url": "http://localhost:8080",
      "description": "Local server"
    }
  ],
  "paths": {
    "/api/familias": {
      "get": {
        "summary": "Listar famílias",
        "operationId": "listarFamilias",
        "parameters": [
          {
            "name": "busca",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lista de famílias retornada com sucesso"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    }
  }
}

4. Usar Token JWT na UI

  1. Fazer login via /auth/login para obter token
  2. Clicar em "Authorize" no topo da Swagger UI
  3. Inserir token no formato: Bearer <token>
  4. Agora todos os endpoints protegidos podem ser testados

🎓 Lições Aprendidas

✅ O que funcionou bem

  • Documentação automática: Anotações geram documentação automaticamente
  • Sempre atualizada: Documentação reflete código atual (sem desatualização)
  • UI interativa: Swagger UI permite testar APIs sem Postman/curl
  • JWT integration: Autenticação JWT funciona perfeitamente na UI

⚠️ Desafios e soluções

  • Anotações verbosas: Muitas anotações podem poluir código. Solução: Usar apenas onde necessário, manter código limpo.
  • Schemas complexos: DTOs complexos podem gerar specs grandes. Solução: Usar @Schema para simplificar.
  • Versionamento: OpenAPI spec muda com código. Solução: Versionar spec junto com código.

📚 Recursos

🔗 Links

Next episode → Day 22/30 — Em desenvolvimento