🚀 Tutorial: Construindo uma API REST de Tarefas com Spring Boot v01
Bem-vindo(a)! Este guia é uma sequência didática projetada para ensinar, passo a passo, como construir uma API RESTful robusta e moderna utilizando Spring Boot. Vamos abordar desde a configuração inicial até práticas avançadas de engenharia de software.
🎯 Objetivo
Ao final deste tutorial, você terá construído uma API completa para um sistema de “Lista de Tarefas” (To-Do List), capaz de realizar as operações de Criar, Ler, Atualizar e Deletar (CRUD).
🛠️ Módulo 1: Preparando o Terreno
1.1 - Configurando o Projeto
Vamos começar criando nosso projeto com o Spring Initializr, a ferramenta oficial para iniciar projetos Spring.
- Acesse start.spring.io.
- Preencha os metadados do projeto:
- Project:
Maven
- Language:
Java
- Spring Boot: Use a versão estável mais recente (ex: 3.x.x).
- Group:
br.com.curso
- Artifact:
todolist-api
- Packaging:
Jar
- Java:
21
(ou a versão que você tiver instalada)
- Project:
- Adicione as seguintes dependências (
Dependencies
):Spring Web
: Para criar APIs REST.Spring Data JPA
: Para facilitar o acesso a dados.H2 Database
: Um banco de dados em memória, ótimo para desenvolvimento.Lombok
: Para reduzir código repetitivo (getters, setters, etc.).Spring Boot DevTools
: Para reinicializações automáticas durante o desenvolvimento.
- Clique em GENERATE e extraia o arquivo
.zip
em seu computador.
1.2 - Estrutura Inicial do Projeto
Após abrir o projeto em sua IDE (IntelliJ, VS Code, Eclipse), a estrutura de pastas será a seguinte:
todolist-api/
├── pom.xml # Arquivo de configuração do Maven com nossas dependências
└── src/
├── main/
│ ├── java/
│ │ └── br/com/curso/todolist/api/
│ │ └── TodolistApiApplication.java # Ponto de entrada da aplicação
│ └── resources/
│ └── application.properties # Configurações da aplicação
└── test/
└── ...
1.3 - Configurando o Banco de Dados
Abra o arquivo src/main/resources/application.properties
e adicione as seguintes linhas para configurar nosso banco de dados H2 em memória:
# Nome da aplicação
spring.application.name=todolist-api
# Habilita o console web do H2 para visualizarmos o banco
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
# Configurações de conexão com o banco
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
# Informa ao Hibernate qual "dialeto" SQL usar
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# Garante que as tabelas sejam criadas antes de tentar inserir dados
spring.jpa.defer-datasource-initialization=true
📦 Módulo 2: A Camada de Dados
Nesta etapa, vamos modelar como os dados de uma “Tarefa” serão armazenados.
2.1 - Criando a Entidade Tarefa
Uma Entidade é uma classe Java que representa uma tabela no banco de dados.
- Crie um novo pacote chamado
tarefa
dentro debr.com.curso.todolist.api
. - Dentro deste pacote, crie a classe
Tarefa.java
.
package br.com.curso.todolist.api.tarefa;
import jakarta.persistence.*;
import lombok.Data;
@Data // Lombok: gera getters, setters, etc.
@Entity // JPA: Marca como uma entidade
@Table(name = "tb_tarefas") // JPA: Define o nome da tabela
public class Tarefa {
@Id // JPA: Marca como chave primária
@GeneratedValue(strategy = GenerationType.IDENTITY) // JPA: Define a geração automática do ID
private Long id;
private String titulo;
private String descricao;
private boolean concluida;
}
2.2 - Diagrama Entidade-Relacionamento (ER)
A classe acima será mapeada para a seguinte estrutura no banco de dados:
erDiagram
TB_TAREFAS {
Long id PK "Chave Primária, Auto-incremento"
String titulo "Título da tarefa"
String descricao "Descrição detalhada"
boolean concluida "Indica se a tarefa foi finalizada"
}
2.3 - Criando o Repositório TarefaRepository
Um Repositório é uma interface que abstrai o acesso aos dados. O Spring Data JPA implementará os métodos para nós!
- No mesmo pacote
tarefa
, crie a interfaceTarefaRepository.java
.
package br.com.curso.todolist.api.tarefa;
import org.springframework.data.jpa.repository.JpaRepository;
public interface TarefaRepository extends JpaRepository<Tarefa, Long> {
}
E é só isso! Agora já temos métodos como save()
, findById()
, findAll()
e deleteById()
prontos para usar.
🧠 Módulo 3: A Camada de Lógica de Negócios
A camada de Serviço orquestra as operações e contém as regras de negócio da nossa aplicação.
- No pacote
tarefa
, crie a classeTarefaService.java
.
package br.com.curso.todolist.api.tarefa;
import org.springframework.stereotype.Service;
import java.util.List;
@Service // Spring: Marca como um componente de serviço
public class TarefaService {
private final TarefaRepository tarefaRepository;
// Injeção de dependência via construtor (prática recomendada)
public TarefaService(TarefaRepository tarefaRepository) {
this.tarefaRepository = tarefaRepository;
}
public List<Tarefa> listarTodas() {
return tarefaRepository.findAll();
}
// Outros métodos (criar, atualizar, etc.) virão aqui...
}
🔌 Módulo 4: Expondo a API com o Controller
O Controller é a porta de entrada da nossa API. Ele recebe as requisições HTTP e as direciona para a camada de serviço.
- No pacote
tarefa
, crie a classeTarefaController.java
.
package br.com.curso.todolist.api.tarefa;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController // Spring: Define que esta classe é um controller REST
@RequestMapping("/tarefas") // Define a URL base para todos os métodos: http://localhost:8080/tarefas
public class TarefaController {
private final TarefaService tarefaService;
public TarefaController(TarefaService tarefaService) {
this.tarefaService = tarefaService;
}
@GetMapping // Mapeia requisições HTTP GET para este método
public List<Tarefa> listarTarefas() {
return tarefaService.listarTodas();
}
}
4.1 - Testando o Primeiro Endpoint
- Execute a aplicação: Rode a classe
TodolistApiApplication.java
. - Acesse no navegador: Abra a URL
http://localhost:8080/tarefas
.
Você deverá ver uma lista vazia []
, pois ainda não temos dados. Vamos adicionar alguns dados de exemplo! Crie o arquivo src/main/resources/data.sql
:
INSERT INTO TB_TAREFAS (TITULO, DESCRICAO, CONCLUIDA) VALUES ('Configurar o Backend', 'Criar a entidade e o repositório da Tarefa.', true);
INSERT INTO TB_TAREFAS (TITULO, DESCRICAO, CONCLUIDA) VALUES ('Criar a API REST', 'Desenvolver o endpoint para listar as tarefas.', false);
Reinicie a aplicação e acesse a URL novamente. Agora você verá os dados em formato JSON!
✨ Módulo 5: Refinando a API com Boas Práticas
Nossa API funciona, mas podemos torná-la muito melhor!
5.1 - O Problema: Expor Entidades na API
Usar a classe @Entity
diretamente na API é arriscado, pois acopla o cliente à estrutura do seu banco de dados. A solução é usar DTOs (Data Transfer Objects).
5.2 - Implementando DTOs e Mappers
Vamos criar DTOs para o “contrato” da nossa API e um Mapper para converter entre Entidade e