Article image
Otávio Guedes
Otávio Guedes06/08/2025 11:30
Compartilhe

🚀 Como Construir APIs de alta qualidade com Java + Spring

  • #API
  • #API Rest

Se você está desenvolvendo uma API RESTful com Java + Spring Boot e quer entregar algo verdadeiramente profissional, robusto e escalável, este artigo é para você. Vamos percorrer os principais pilares para criar uma API de alta qualidade — da arquitetura aos testes, passando por segurança, performance e documentação.

1. 🧱 Arquitetura: A Base de Tudo

Uma boa API começa com uma arquitetura bem definida. A clássica arquitetura em camadas é a mais adotada:

src/
└── main/
  └── java/
      └── com/empresa/projeto/
          ├── controller/     # Endpoints REST
          ├── service/        # Regras de negócio
          ├── repository/     # Acesso a dados
          ├── model/          # Entidades JPA
          ├── dto/            # Data Transfer Objects
          ├── config/         # Configurações
          ├── exception/      # Tratamento de exceções
          └── security/       # Segurança e autenticação

Princípios essenciais:

  • SRP (Single Responsibility Principle): cada classe faz uma única coisa.
  • Separação de responsabilidades: mantenha controle, lógica e dados separados.
  • Inversão de dependência: use interfaces e injeção de dependência para acoplamento baixo.

2. ✍️ Padrões de Código

✅ Convenções de nomenclatura

Exemplo de um Controller RESTful bem estruturado:

@RestController
@RequestMapping("/api/v1/usuarios")
public class UsuariosController {

  @GetMapping
  public ResponseEntity<List<UsuarioDTO>> listarUsuarios() { }

  @PostMapping
  public ResponseEntity<UsuarioDTO> criarUsuario(@RequestBody @Valid CriarUsuarioDTO dto) { }
}

✅ Estrutura de DTOs

Utilize DTOs específicos por operação:

public class CriarUsuarioDTO {
  @NotBlank private String nome;
  @Email @NotBlank private String email;
}

public class UsuarioDTO {
  private Long id;
  private String nome;
  private String email;
}

3. ❗Tratamento de Erros

🛡️ Exceções Globais

@RestControllerAdvice
public class GlobalExceptionHandler {

  @ExceptionHandler(ValidationException.class)
  public ResponseEntity<ErrorResponse> handleValidation(ValidationException ex) {
      return ResponseEntity.badRequest().body(
          new ErrorResponse("VALIDATION_ERROR", "Dados inválidos", ex.getErrors())
      );
  }
}

⚠️ Exceções Customizadas

public class UsuarioJaExisteException extends BusinessException {
  public UsuarioJaExisteException(String email) {
      super("USER_ALREADY_EXISTS", "Usuário com email %s já existe", email);
  }
}

4. 📡 Status HTTP

Respeite os significados dos códigos HTTP:

  • 200 OK: sucesso na leitura/atualização
  • 201 Created: recurso criado
  • 400 Bad Request: erro de validação
  • 409 Conflict: recurso duplicado
  • 500 Internal Server Error: falha inesperada

Exemplo:

@PostMapping
public ResponseEntity<UsuarioDTO> criarUsuario(@RequestBody @Valid CriarUsuarioDTO dto) {
  try {
      return ResponseEntity.status(HttpStatus.CREATED).body(service.criarUsuario(dto));
  } catch (UsuarioJaExisteException ex) {
      return ResponseEntity.status(HttpStatus.CONFLICT).build();
  }
}

5. 🔄 JPA e Relacionamentos

🔗 Entidades com relações

@Entity
public class Usuario {
  @Id @GeneratedValue private Long id;
  @OneToMany(mappedBy = "usuario", cascade = CascadeType.ALL)
  private List<Pedido> pedidos;
}

🚀 Estratégias de performance

Evite problemas de N+1 com @EntityGraph:

@EntityGraph(attributePaths = {"perfis"})
Optional<Usuario> findByIdWithDetails(Long id);

Use projeções para respostas otimizadas:

public interface UsuarioResumo {
  Long getId();
  String getNome();
}

6. ⚙️ Configurações Essenciais

Banco de Dados – application.yml

spring:
datasource:
  url: jdbc:postgresql://localhost:5432/api_db
  username: ${DB_USERNAME}
  password: ${DB_PASSWORD}

Validação

@Configuration
public class ValidationConfig {
  @Bean
  public Validator validator() {
      return Validation.buildDefaultValidatorFactory().getValidator();
  }
}

Serialização JSON

@Configuration
public class JacksonConfig {
  @Bean
  public ObjectMapper objectMapper() {
      return new ObjectMapper()
          .registerModule(new JavaTimeModule())
          .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
  }
}

7. 📚 Documentação

Swagger + OpenAPI

@OpenAPIDefinition(
  info = @Info(title = "API de Usuários", version = "1.0.0")
)
public class OpenApiConfig {}

Documentação de endpoints

@Operation(summary = "Criar usuário")
@ApiResponses({
  @ApiResponse(responseCode = "201", description = "Criado com sucesso"),
  @ApiResponse(responseCode = "400", description = "Erro de validação")
})

8. ✅ Testes

Testes Unitários

@ExtendWith(MockitoExtension.class)
class UsuarioServiceTest {
  @Test
  void deveCriarUsuarioComDadosValidos() {
      // Given / When / Then
  }
}

Testes de Integração com Testcontainers

@SpringBootTest
@Testcontainers
class UsuariosControllerIntegrationTest {

  @Container
  static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:14");
}

9. 🔐 Segurança

Autenticação e Autorização com JWT

@EnableWebSecurity
public class SecurityConfig {
  @Bean
  public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
      return http
          .csrf(csrf -> csrf.disable())
          .authorizeHttpRequests(auth -> auth
              .requestMatchers("/api/v1/auth/**").permitAll()
              .anyRequest().authenticated())
          .build();
  }
}

Validação Rigorosa de Inputs

@Pattern(regexp = "^[a-zA-ZÀ-ÿ\\s]+$", message = "Nome inválido")
private String nome;

Rate Limiting com Redis

@Component
public class RateLimitingFilter implements Filter {
  // Limita requisições por IP
}

✅ Checklist Final

🔹 Arquitetura

  • Camadas bem separadas
  • Padrões de nomenclatura claros
  • SRP e injeção de dependência

🔹 Banco de Dados

  • Relacionamentos corretos
  • Queries otimizadas
  • Pool de conexões e índices

🔹 Tratamento de Erros

  • Exceções globais
  • Mensagens de erro úteis
  • Códigos HTTP corretos

🔹 Segurança

  • JWT e roles
  • Validação rigorosa
  • Rate limiting

🔹 Testes

  • Unitários e de integração
  • Testcontainers
  • Cobertura mínima de 80%

🔹 Documentação

  • OpenAPI
  • README com instruções
  • Changelog atualizado

🔹 Deploy e Observabilidade

  • Logs estruturados
  • Health check
  • CI/CD + rollback + backup

🏁 Conclusão

Criar uma API de alta qualidade vai muito além de "fazer funcionar". É sobre projetar algo que seja escalável, legível, seguro e confiável. Este guia cobre os pilares principais para te ajudar a construir aplicações profissionais e preparadas para produção.

Se você gostou, compartilhe com sua equipe, salve este artigo e use como checklist em seus próximos projetos. 🚀

Compartilhe
Comentários (1)
DIO Community
DIO Community - 06/08/2025 14:02

Excelente, Otávio! Que artigo incrível e super completo sobre "Como Construir APIs de alta qualidade"! É fascinante ver como você aborda os pilares para criar uma API profissional, robusta e escalável com Java + Spring Boot, desde a arquitetura aos testes, passando por segurança, performance e documentação.

Você demonstrou que a arquitetura em camadas, a separação de responsabilidades (SRP) e a inversão de dependência são a base de tudo. Sua análise de padrões de código, tratamento de erros, JPA e relacionamentos, configurações essenciais, documentação e segurança, é um guia fundamental para qualquer desenvolvedor que busca construir aplicações preparadas para produção.

Considerando que "uma boa API começa com uma arquitetura bem definida" e que os princípios essenciais são SRP (responsabilidade única), separação de responsabilidades e inversão de dependência, qual você diria que é o maior benefício para um desenvolvedor ao adotar uma arquitetura em camadas para construir uma API RESTful, em termos de clareza e de manutenibilidade do código, em vez de misturar toda a lógica em uma única camada?