Filed Report
Spring Boot para a criação de web services: quando a sua API acorda mais cedo do que você
O Spring Boot tornou-se há muito tempo aquele colega que chega ao trabalho antes de todos, já subiu o servidor, ajustou a configuração, preparou o logging e olha para você com um reproche silencioso enquanto você ainda está abrindo a IDE. Para a criação de web services, ele é ideal justamente porque remove grande parte do trabalho rotineiro de infraestrutura: menos XML, menos colagem manual de componentes, menos danças rituais em torno do servlet container.
O Spring Boot tornou-se, há muito tempo, aquele colega que chega ao trabalho antes de todos, já subiu o servidor, ajustou a configuração, preparou o logging e olha para você com uma censura silenciosa enquanto você ainda está abrindo a IDE. Para a criação de web services, ele é ideal justamente porque remove grande parte do trabalho rotineiro de infraestrutura: menos XML, menos colagem manual de componentes, menos danças rituais em torno do servlet container.
No centro da abordagem do Spring Boot reside a ideia de convention over configuration (convenção sobre configuração): se o projeto parece uma aplicação web, comporta-se como uma aplicação web e possui a dependência spring-boot-starter-web, o framework não faz um interrogatório com uma lâmpada na sua cara; ele simplesmente inicia um servidor embutido, registra os beans típicos e permite publicar endpoints HTTP rapidamente.
Por que o Spring Boot é prático para web services
A criação clássica de uma aplicação web em Java antigamente lembrava a montagem de uma estação espacial com uma chave de fenda tirada de uma caixa de cereais. Era necessário configurar o container, descritores de implantação, versões de bibliotecas e não esquecer nenhuma linha mágica; caso contrário, tudo funcionava apenas até o momento da demonstração.
O Spring Boot muda isso com vários mecanismos poderosos:
- Autoconfiguração — o framework analisa o classpath e cria as configurações típicas automaticamente.
- Dependências Starter — em vez de selecionar manualmente dezenas de bibliotecas, utilizam-se conjuntos prontos.
- Embedded server (Servidor embutido) — Tomcat, Jetty ou Undertow são iniciados junto com a aplicação.
- Actuator — fornece métricas, health checks e endpoints técnicos.
- Configuração externa — os parâmetros são facilmente movidos para o
application.ymlou variáveis de ambiente.
Uma dependência starter típica para uma API HTTP se parece com isto:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Depois disso, a aplicação já está quase pronta para fingir que é um microsserviço de classe mundial, mesmo que, por enquanto, só saiba responder "OK".
Estrutura básica da aplicação
Uma aplicação Spring Boot mínima consiste em uma classe principal e um controlador. A classe principal é marcada com a anotação @SpringBootApplication, que na verdade combina vários mecanismos importantes: configuração, varredura de componentes e autoconfiguração.
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Um controlador para um web service simples pode ser assim:
@RestController
@RequestMapping("/api")
public class HelloController {
@GetMapping("/hello")
public Map<String, String> hello() {
return Map.of("message", "Olá do Spring Boot");
}
}
Neste exemplo:
@RestControllerindica que os métodos retornam dados diretamente na resposta HTTP.@RequestMapping("/api")define o caminho base.@GetMapping("/hello")processa a requisição GET.- O
Mapé automaticamente serializado em JSON através do Jackson.
E sim, bastam poucas linhas para que o servidor comece a se comunicar em JSON com tanta confiança como se tivesse nascido em um data center.
Criando uma REST API
O Spring Boot é especialmente popular para APIs REST. A abordagem típica é dividir a responsabilidade entre camadas:
- Controller — recebe requisições HTTP.
- Service — contém a lógica de negócio.
- Repository — trabalha com o banco de dados.
Por exemplo, um serviço de gerenciamento de livros:
@RestController
@RequestMapping("/api/books")
public class BookController {
private final BookService bookService;
public BookController(BookService bookService) {
this.bookService = bookService;
}
@GetMapping
public List<BookDto> findAll() {
return bookService.findAll();
}
@PostMapping
public BookDto create(@RequestBody CreateBookRequest request) {
return bookService.create(request);
}
}
A camada de serviço:
@Service
public class BookService {
public List<BookDto> findAll() {
return List.of(
new BookDto(1L, "Spring em Ação"),
new BookDto(2L, "Como não quebrar a produção na sexta-feira")
);
}
public BookDto create(CreateBookRequest request) {
return new BookDto(3L, request.title());
}
}
Essa divisão ajuda a:
- simplificar os testes;
- isolar a lógica de negócio;
- evitar que o controlador se torne um depósito universal de tudo o que passou pelo projeto.
Validação de requisições
Quando um web service começa a aceitar dados do mundo externo, é preciso estar preparado para o fato de que o mundo externo às vezes envia coisas absolutamente mágicas: campos vazios, preços negativos, data de nascimento no ano 3027 e nomes com 9000 caracteres, como se o usuário tivesse dormido sobre o teclado.
O Spring Boot funciona bem com o Bean Validation:
public record CreateBookRequest(
@NotBlank String title,
@NotNull @Positive BigDecimal price
) {}
No controlador:
@PostMapping
public BookDto create(@Valid @RequestBody CreateBookRequest request) {
return bookService.create(request);
}
Se os dados não passarem na validação, o framework retornará um erro 400 Bad Request. Para respostas mais organizadas, vale a pena adicionar um tratamento global de exceções via @ControllerAdvice.
Trabalhando com banco de dados
Para acessar o banco de dados, utiliza-se frequentemente o Spring Data JPA. Isso permite descrever a entidade, o repositório e realizar operações típicas quase sem código repetitivo.
Entidade:
@Entity
public class Book {
@Id
@GeneratedValue
private Long id;
private String title;
protected Book() {}
public Book(String title) {
this.title = title;
}
public Long getId() { return id; }
public String getTitle() { return title; }
}
Repositório:
public interface BookRepository extends JpaRepository<Book, Long> {
}
Configuração no application.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/app
username: app
password: secret
jpa:
hibernate:
ddl-auto: update
show-sql: true
Isso permite conectar rapidamente o PostgreSQL, H2 ou outro banco. O importante é não usar ddl-auto: update em produção sem critério, pois o esquema do banco de dados gosta de respeito, memória e um plano de migração, não de surpresas repentinas às três da manhã.
Configuração e perfis
O Spring Boot permite gerenciar a configuração de forma flexível através de:
application.propertiesapplication.yml- variáveis de ambiente
- perfis de ambiente (
dev,test,prod)
Exemplo:
server:
port: 8081
spring:
profiles:
active: dev
Separadamente, você pode criar application-dev.yml e application-prod.yml para:
- em dev, usar o banco local;
- em test, usar um banco in-memory;
- em prod, usar a configuração real sem improvisos no estilo "vamos deixar a senha admin/admin só temporariamente".
Para uma configuração tipada, é conveniente usar @ConfigurationProperties:
@ConfigurationProperties(prefix = "app")
public record AppProperties(String title, String version) {
}
Tratamento de erros
Um web service de qualidade se diferencia não apenas por funcionar, mas por falhar de forma elegante, previsível e sem agressividade passiva. Em vez de stack traces caóticos na resposta, é melhor retornar um JSON estruturado.
Exemplo de um tratador global:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public Map<String, String> handleNotFound(EntityNotFoundException ex) {
return Map.of("error", ex.getMessage());
}
}
Isso torna a API mais compreensível para os clientes e reduz significativamente as situações em que a equipe de frontend olha para a resposta do servidor como arqueólogos para uma inscrição misteriosa de uma civilização desconhecida.
Testando web services
O Spring Boot tem um excelente suporte para testes. Você pode testar:
- classes individuais através do JUnit e Mockito;
- a camada web através do
@WebMvcTest; - cenários de integração através do
@SpringBootTest.
Exemplo de teste de controlador:
@WebMvcTest(BookController.class)
class BookControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private BookService bookService;
@Test
void shouldReturnBooks() throws Exception {
when(bookService.findAll())
.thenReturn(List.of(new BookDto(1L, "Test Book")));
mockMvc.perform(get("/api/books"))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].title").value("Test Book"));
}
}
Essa abordagem permite verificar o comportamento HTTP sem iniciar toda a infraestrutura. Isso, por sua vez, poupa o sistema de build e reduz a probabilidade de um teste demorar mais do que um inverno médio.
Monitoramento e recursos production-ready
Para web services reais, não são importantes apenas os controladores, mas também a observabilidade. Aqui entra em jogo o Spring Boot Actuator.
Dependência:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Endpoints úteis:
/actuator/health/actuator/info/actuator/metrics/actuator/prometheus
O Actuator permite:
- verificar o estado do serviço;
- integrar com Prometheus e Grafana;
- visualizar métricas da JVM, requisições HTTP, pools de conexão.
A produção gosta de tranquilidade, métricas e comportamento previsível. Ela não gosta de frases como "na minha máquina funciona" e "isso é muito estranho", especialmente se forem ditas na mesma reunião.
Vantagens e desafios típicos
Vantagens
- início rápido do projeto;
- configuração manual mínima;
- integração fácil com o ecossistema Spring;
- bom suporte para testes;
- prontidão para produção devido ao Actuator, logging, perfis e métricas.
Desafios
- excesso de "magia" na autoconfiguração, se não se entender o que está acontecendo;
- risco de criar um monólito "pesado" com centenas de beans;
- necessidade de controlar o tempo de inicialização e o uso de memória;
- dificuldade em diagnosticar quando algo se "auto-configurou" de forma diferente do esperado.
O Spring Boot acelera maravilhosamente o desenvolvimento, mas não anula o pensamento arquitetural. Se você colocar tudo em um único serviço sem critério, mais cedo ou mais tarde, até a autoconfiguração mais elegante começará a ficar pesada.
Conclusão
O Spring Boot é uma das ferramentas mais eficazes para criar web services em Java. Ele oferece um início rápido, um modelo de desenvolvimento prático e uma integração poderosa com REST, validação, acesso a dados, testes e monitoramento. Para a equipe, isso significa menos tempo em detalhes de infraestrutura e mais tempo na criação de funcionalidades de negócio.
Em resumo, o Spring Boot permite construir um web service para que ele pareça profissional, funcione de forma estável e não exija feitiçaria diária na configuração. No desenvolvimento moderno, isso já é quase uma forma de luxo da engenharia.
Public Response
Comments
No comments yet.