Spring Boot API REST

Spring Boot para Iniciantes: Construindo APIs REST do Zero

,

Se você está começando sua jornada no desenvolvimento Java e quer aprender a criar APIs REST modernas, o Spring Boot é a ferramenta ideal para começar. Neste artigo, vamos construir uma API REST completa do zero, explicando cada conceito de forma simples e prática.

O que é Spring Boot?

Spring Boot é um framework Java que simplifica drasticamente a criação de aplicações Spring. Ele elimina a necessidade de configurações complexas, oferecendo:

  • Configuração automática: Detecta automaticamente as dependências e configura o projeto
  • Servidor embutido: Não precisa instalar Tomcat ou outros servidores
  • Gerenciamento de dependências: Resolve conflitos de versões automaticamente
  • Produção pronta: Inclui recursos como métricas, verificação de saúde e monitoramento

Por que Usar Spring Boot para APIs REST?

Criar APIs REST com Spring Boot oferece várias vantagens:

  • Rapidez no desenvolvimento: Menos código boilerplate
  • Padrões estabelecidos: Segue as melhores práticas da indústria
  • Ecossistema rico: Integração fácil com bancos de dados, segurança, testes
  • Comunidade ativa: Vasta documentação e suporte

Configurando o Ambiente

Pré-requisitos

Antes de começar, certifique-se de ter:

  • Java 11 ou superior instalado
  • IDE (IntelliJ IDEA, Eclipse ou VS Code)
  • Maven ou Gradle (usaremos Maven neste tutorial)

Criando o Projeto

A forma mais fácil de criar um projeto Spring Boot é através do Spring Initializr:

  1. Acesse https://start.spring.io/
  2. Selecione:
    • Project: Maven Project
    • Language: Java
    • Spring Boot: 3.1.x (versão estável mais recente)
    • Packaging: Jar
    • Java: 11 ou superior
  3. Adicione as dependências:
    • Spring Web
    • Spring Data JPA
    • H2 Database (para desenvolvimento)
    • Spring Boot DevTools
  4. Click em “Generate” para baixar o projeto

Estrutura do Projeto

Após extrair o projeto, você verá esta estrutura:

meu-projeto/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com.exemplo.projeto/
│   │   │       └── ProjetoApplication.java
│   │   └── resources/
│   │       ├── application.properties
│   │       └── static/
│   └── test/
├── pom.xml
└── mvnw

Construindo Nossa Primeira API

Vamos criar uma API simples para gerenciar produtos. Começaremos definindo nossa entidade.

1. Criando a Entidade Produto

Crie a classe Produto.java no pacote principal:

package com.exemplo.projeto.model;

import jakarta.persistence.*;

@Entity
@Table(name = "produtos")
public class Produto {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false)
    private String nome;
    
    @Column(nullable = false)
    private Double preco;
    
    private String descricao;
    
    // Construtores
    public Produto() {}
    
    public Produto(String nome, Double preco, String descricao) {
        this.nome = nome;
        this.preco = preco;
        this.descricao = descricao;
    }
    
    // Getters e Setters
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getNome() { return nome; }
    public void setNome(String nome) { this.nome = nome; }
    
    public Double getPreco() { return preco; }
    public void setPreco(Double preco) { this.preco = preco; }
    
    public String getDescricao() { return descricao; }
    public void setDescricao(String descricao) { this.descricao = descricao; }
}

Explicando as anotações:

  • @Entity: Marca a classe como uma entidade JPA
  • @Table: Define o nome da tabela no banco
  • @Id: Marca o campo como chave primária
  • @GeneratedValue: Configura a geração automática do ID
  • @Column: Configura propriedades da coluna

2. Criando o Repository

O Repository é responsável pelo acesso aos dados:

package com.exemplo.projeto.repository;

import com.exemplo.projeto.model.Produto;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ProdutoRepository extends JpaRepository<Produto, Long> {
    // Métodos personalizados (se necessário)
    List<Produto> findByNomeContaining(String nome);
    List<Produto> findByPrecoLessThan(Double preco);
}

O JpaRepository já fornece métodos prontos como:

  • save() – salvar/atualizar
  • findById() – buscar por ID
  • findAll() – listar todos
  • deleteById() – deletar por ID

3. Criando o Controller

O Controller gerencia as requisições HTTP:

package com.exemplo.projeto.controller;

import com.exemplo.projeto.model.Produto;
import com.exemplo.projeto.repository.ProdutoRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/api/produtos")
public class ProdutoController {
    
    @Autowired
    private ProdutoRepository produtoRepository;
    
    // GET /api/produtos - Listar todos os produtos
    @GetMapping
    public List<Produto> listarTodos() {
        return produtoRepository.findAll();
    }
    
    // GET /api/produtos/{id} - Buscar produto por ID
    @GetMapping("/{id}")
    public ResponseEntity<Produto> buscarPorId(@PathVariable Long id) {
        Optional<Produto> produto = produtoRepository.findById(id);
        return produto.map(ResponseEntity::ok)
                     .orElse(ResponseEntity.notFound().build());
    }
    
    // POST /api/produtos - Criar novo produto
    @PostMapping
    public Produto criar(@RequestBody Produto produto) {
        return produtoRepository.save(produto);
    }
    
    // PUT /api/produtos/{id} - Atualizar produto
    @PutMapping("/{id}")
    public ResponseEntity<Produto> atualizar(@PathVariable Long id, 
                                           @RequestBody Produto produtoAtualizado) {
        return produtoRepository.findById(id)
                .map(produto -> {
                    produto.setNome(produtoAtualizado.getNome());
                    produto.setPreco(produtoAtualizado.getPreco());
                    produto.setDescricao(produtoAtualizado.getDescricao());
                    return ResponseEntity.ok(produtoRepository.save(produto));
                })
                .orElse(ResponseEntity.notFound().build());
    }
    
    // DELETE /api/produtos/{id} - Deletar produto
    @DeleteMapping("/{id}")
    public ResponseEntity<?> deletar(@PathVariable Long id) {
        return produtoRepository.findById(id)
                .map(produto -> {
                    produtoRepository.delete(produto);
                    return ResponseEntity.ok().build();
                })
                .orElse(ResponseEntity.notFound().build());
    }
}

Explicando as anotações:

  • @RestController: Marca a classe como um controller REST
  • @RequestMapping: Define a URL base para todos os endpoints
  • @GetMapping, @PostMapping, etc.: Mapeia métodos HTTP específicos
  • @PathVariable: Captura valores da URL
  • @RequestBody: Converte JSON em objeto Java automaticamente

4. Configurando o Banco de Dados

Para desenvolvimento, vamos usar o H2 (banco em memória). Adicione no application.properties:

# Configuração do H2
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

# Console do H2
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

# JPA/Hibernate
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

Testando a API

1. Executando a Aplicação

Execute a classe principal ProjetoApplication.java ou use o comando:

mvn spring-boot:run

A aplicação iniciará na porta 8080.

2. Testando com Postman ou cURL

Criar um produto:

curl -X POST http://localhost:8080/api/produtos \
  -H "Content-Type: application/json" \
  -d '{
    "nome": "Notebook",
    "preco": 2500.00,
    "descricao": "Notebook para desenvolvimento"
  }'

Listar produtos:

curl http://localhost:8080/api/produtos

Buscar por ID:

curl http://localhost:8080/api/produtos/1

Melhorias e Boas Práticas

1. Validação de Dados

Adicione validações na entidade:

import jakarta.validation.constraints.*;

@Entity
public class Produto {
    
    @NotBlank(message = "Nome é obrigatório")
    @Size(min = 2, max = 100, message = "Nome deve ter entre 2 e 100 caracteres")
    private String nome;
    
    @NotNull(message = "Preço é obrigatório")
    @DecimalMin(value = "0.01", message = "Preço deve ser maior que zero")
    private Double preco;
    
    // ...
}

No controller, adicione @Valid:

@PostMapping
public Produto criar(@Valid @RequestBody Produto produto) {
    return produtoRepository.save(produto);
}

2. Tratamento de Exceções

Crie um handler global para exceções:

@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, String>> handleValidationExceptions(
            MethodArgumentNotValidException ex) {
        
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getAllErrors().forEach((error) -> {
            String fieldName = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errors.put(fieldName, errorMessage);
        });
        
        return ResponseEntity.badRequest().body(errors);
    }
}

3. DTOs (Data Transfer Objects)

Para separar a representação interna dos dados da API:

public class ProdutoDTO {
    private String nome;
    private Double preco;
    private String descricao;
    
    // Construtores, getters e setters
}

Próximos Passos

Agora que você tem uma API básica funcionando, considere explorar:

Recursos Avançados

  • Spring Security: Para autenticação e autorização
  • Spring Data JPA: Consultas mais complexas
  • Documentação com Swagger: Para documentar sua API automaticamente
  • Testes: Unitários e de integração com Spring Boot Test

Banco de Dados

  • PostgreSQL/MySQL: Para ambiente de produção
  • Flyway/Liquibase: Para versionamento do banco
  • Connection Pool: Para otimizar conexões

Deploy e Monitoramento

  • Docker: Para containerização
  • Spring Boot Actuator: Para monitoramento
  • Logs estruturados: Com Logback
  • Profiles: Para diferentes ambientes (dev, test, prod)

Conclusão

O Spring Boot revoluciona o desenvolvimento de APIs REST em Java, oferecendo uma experiência de desenvolvimento rápida e produtiva. Com apenas algumas anotações, criamos uma API completa com operações CRUD, validação e tratamento de erros.

Este é apenas o começo da sua jornada com Spring Boot. O framework oferece uma vasta gama de funcionalidades que podem ser exploradas conforme suas necessidades crescem. Continue praticando, explore a documentação oficial e experimente novos recursos.

Lembre-se: A prática constante é fundamental para dominar qualquer tecnologia. Comece com projetos simples e vá aumentando a complexidade gradualmente.


Gostou deste tutorial? Deixe seu comentário e compartilhe suas dúvidas. No próximo artigo, abordaremos como adicionar segurança à nossa API com Spring Security.

Tags

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *