Aula 03 - Introdução às APIS REST e ao Spring Boot
Nesta aula apresentaremos uma introdução aos conceitos basilares para construção de uma API REST para gerenciar uma lista de contatos utilizando Spring Boot. A ideia é demonstrar, passo a passo, como criar um projeto Spring Boot e expor métodos que permitem a criação, consulta, atualização e exclusão de contatos (operações conhecidas como CRUD). Antes disso, entretanto, é preciso definir alguns conceitos.
1. O que é uma API?
Uma API (Application Programming Interface) é um conjunto de regras e definições que permitem que diferentes sistemas de software se comuniquem entre si. Elas atuam como intermediárias que possibilitam que um sistema solicite e envie dados para outro, de maneira estruturada e padronizada.
Dentre os diversos estilos de arquitetura para APIs, uma das mais populares e amplamente utilizadas hoje em dia é a API REST (Representational State Transfer). Esse padrão se baseia nos princípios da web, utilizando o protocolo HTTP para a comunicação entre sistemas distribuídos.
1.1 O que é uma API REST?
O termo REST (Representational State Transfer) foi criado por Roy Fielding em sua tese de doutorado em 2000. Ele descreveu um conjunto de princípios arquiteturais que utilizam os padrões já estabelecidos na web para criar sistemas escaláveis e eficientes.
Uma API REST segue esses princípios, permitindo que os dados sejam manipulados através de recursos (resources), representados por URLs (Uniform Resource Locators) e acessados usando os métodos HTTP padrão:
- GET → Obtém um recurso (ex.: buscar lista de usuários).
- POST → Cria um novo recurso (ex.: cadastrar um novo usuário).
- PUT → Atualiza um recurso existente (ex.: editar os dados de um usuário).
- PATCH → Atualiza parcialmente um recurso (ex.: modificar apenas um campo específico de um usuário).
- DELETE → Remove um recurso (ex.: excluir um usuário).
Esses métodos garantem que a API siga uma estrutura previsível e intuitiva para desenvolvedores que a utilizam. Isso acontece pois o uso adequado dos métodos HTTP em APIs REST garante padronização, previsibilidade e intuitividade para os desenvolvedores que consomem a API. Ou seja, ao interagir com qualquer API REST bem projetada, um desenvolvedor já pode inferir como fazer requisições apenas conhecendo os métodos e os recursos expostos.
Se uma API segue corretamente os padrões REST, um desenvolvedor não precisa consultar a documentação sempre que for fazer uma chamada, pois os métodos HTTP seguem uma convenção universal.
1.2 Exemplo de Convenção em APIs REST
Vamos imaginar uma API para gerenciar usuários (users
). Seguindo a convenção
REST, os endpoints e métodos HTTP devem funcionar assim:
Ação Desejada | Método HTTP | Caminho (URI) | Corpo da Requisição | Resposta Esperada |
---|---|---|---|---|
Obter todos os usuários | GET | /users |
❌ (sem corpo) | Lista de usuários (JSON) |
Obter um usuário pelo ID | GET | /users/{id} |
❌ (sem corpo) | JSON do usuário |
Criar um novo usuário | POST | /users |
✅ JSON com os dados do usuário | JSON do usuário criado com ID gerado |
Atualizar todo um usuário existente | PUT | /users/{id} |
✅ JSON com todos os campos do usuário | JSON do usuário atualizado |
Atualizar parcialmente um usuário | PATCH | /users/{id} |
✅ JSON com apenas os campos alterados | JSON do usuário atualizado |
Excluir um usuário | DELETE | /users/{id} |
❌ (sem corpo) | Resposta vazia (status HTTP 204) |
Por que isso faz sentido?
Se um desenvolvedor encontrar uma API com o recurso products
(produtos), ele já pode inferir como
a API funciona sem ler a documentação, pois seguirá o mesmo padrão:
Ação Desejada | Método HTTP | Caminho (URI) |
---|---|---|
Obter todos os produtos | GET | /products |
Obter um produto pelo ID | GET | /products/{id} |
Criar um novo produto | POST | /products |
Atualizar um produto | PUT | /products/{id} |
Atualizar um campo do produto | PATCH | /products/{id} |
Excluir um produto | DELETE | /products/{id} |
Isso garante que, se um desenvolvedor aprender a consumir uma API REST, ele poderá consumir qualquer outra API REST bem estruturada sem precisar reaprender cada API do zero. Na seção 2.5 é apresentado o código fonte da implementação de um Controller de uma aplicação Spring Boot que segue a convenção descrita acima.
Ainda em relação à convenção, é importante o uso adequado dos verbos PUT e PATCH.
1.3 Diferença entre PUT e PATCH
Tanto o PUT quanto o PATCH são usados para atualizar recursos, mas com diferenças importantes:
Método | Propósito | Tipo de Atualização | Exemplo de Uso |
---|---|---|---|
PUT | Atualiza um recurso inteiro | Substitui completamente os dados | Atualizar todas as informações de um usuário |
PATCH | Atualiza parcialmente um recurso | Modifica apenas os campos enviados na requisição | Atualizar apenas o e-mail de um usuário |
Exemplo de Requisição PUT
Se temos um usuário cadastrado assim:
{
"id": 1,
"nome": "João Silva",
"email": "joao@email.com",
"telefone": "9999-9999"
}
E enviamos um PUT com este corpo:
{
"id": 1,
"nome": "Maria Silva",
"email": "maria@email.com",
"telefone": "8888-8888"
}
O registro original será completamente substituído, mesmo que não tenha havido mudanças no ID.
Exemplo de Requisição PATCH
Se enviarmos um PATCH apenas com:
{
"email": "email_atualizado@email.com"
}
Apenas o campo email
será alterado, e os outros campos permanecerão inalterados.
1.4 Utilização de APIs REST
Em relação à aplicabilidade, as APIs REST são amplamente utilizadas em diversos cenários do desenvolvimento de software, incluindo:
-
Aplicações Web e Mobile:
- APIs REST são a base para aplicativos móveis e front-ends modernos, permitindo que o cliente (navegador ou aplicativo) se comunique com servidores back-end.
- Exemplo: O aplicativo de um banco acessa os dados do usuário através de uma API REST.
-
Integração entre Sistemas:
- Diferentes sistemas podem se comunicar via APIs REST, eliminando a necessidade de compartilhamento de banco de dados.
- Exemplo: Um ERP de uma empresa pode se integrar ao sistema de contabilidade por meio de uma API.
-
Serviços em Nuvem e IoT:
- Dispositivos IoT (Internet das Coisas) frequentemente usam APIs REST para enviar dados para servidores.
- Exemplo: Um smartwatch pode enviar informações de batimentos cardíacos para uma API REST na nuvem.
-
Plataformas de Terceiros:
- Muitas empresas oferecem APIs REST para que terceiros utilizem seus serviços de forma programática.
- Exemplo: O Google Maps fornece APIs REST para que desenvolvedores integrem mapas em seus aplicativos.
1.5 Vantagens das APIs REST
-
Simplicidade e Facilidade de Uso
- As APIs REST utilizam o protocolo HTTP, que é amplamente conhecido e usado na web.
- O uso de JSON como formato de dados facilita a leitura e escrita, tornando a comunicação leve e eficiente.
-
Escalabilidade
- Por serem stateless (não armazenam estado entre requisições), as APIs REST facilitam a escalabilidade horizontal, permitindo múltiplos servidores processando requisições simultaneamente.
-
Flexibilidade e Independência
- REST permite que clientes em diferentes tecnologias (React, Angular, iOS, Android) consumam a mesma API sem alterações no servidor.
-
Padronização e Interoperabilidade
- Como segue padrões bem definidos, uma API REST pode ser usada por qualquer cliente que compreenda HTTP.
-
Cacheável
- APIs REST permitem o uso eficiente de cache, reduzindo a carga no servidor e melhorando a performance.
É importante notar, entretanto, que não basta fazer as chamadas dos métodos HTTP para que se tenha uma API REST.
1.6 Modelo de Maturidade de Richardson
Nesse sentido, o Modelo de Maturidade de Richardson (RMM - Richardson Maturity Model) foi criado pelo cientista da computação Leonard Richardson e apresentado em 2008 durante uma palestra na QCon, uma conferência sobre desenvolvimento de software. Esse modelo propõe uma forma de avaliar o nível de conformidade de uma API com os princípios REST, ajudando a medir quão bem uma API segue a filosofia RESTful descrita por Roy Fielding em sua tese de doutorado em 2000.
A motivação principal desse modelo é a observação de que nem todas as APIs chamadas de "REST" realmente seguem os princípios REST. Muitas APIs usam apenas HTTP como meio de transporte, mas continuam operando como sistemas antigos, sem aproveitar os benefícios reais do REST. O modelo de Richardson classifica APIs em quatro níveis de maturidade, destacando aspectos como a organização de recursos, o uso correto dos métodos HTTP e a adoção de hipermídia (HATEOAS).
Os Quatro Níveis do Modelo de Richardson
O modelo define quatro níveis de maturidade, numerados de 0 a 3, onde cada nível indica uma progressão rumo a uma API verdadeiramente RESTful.
Nível 0 - "O Ponto de Entrada Único" (The Swamp of POX - Plain Old XML)
Neste nível, a API não utiliza os conceitos REST. Em vez disso, ela usa HTTP apenas como meio de transporte para mensagens genéricas, muitas vezes enviando e recebendo dados em formatos como XML ou JSON, sem aproveitar a estrutura do protocolo HTTP.
Exemplo Histórico: APIs Baseadas em RPC ou SOAP
- Antes da adoção de REST, muitas APIs eram construídas utilizando SOAP (Simple Object Access Protocol), que encapsula mensagens XML dentro de requisições HTTP.
- As APIs SOAP normalmente usavam apenas um único endpoint, como
/service
, e todas as operações eram diferenciadas pelo conteúdo do corpo da requisição. - Como consequência, HTTP era tratado apenas como um canal de transporte, sem o uso adequado de métodos como GET, POST, PUT e DELETE. Ainda há usos para SOAP, que serão discutidos posteriormente, mas de forma geral sua utilização é atualmente restrita à casos específicos.
- Exemplo real: Serviços SOAP do governo dos EUA nos anos 2000 (exemplo: APIs SOAP do IRS para comunicação entre sistemas fiscais).
Nível 1 - "Recursos" (Resources)
No Nível 1, a API começa a organizar seus dados em recursos individuais e cada recurso recebe uma URL única. No entanto, os métodos HTTP ainda não são utilizados corretamente, e a API continua tratando HTTP apenas como um meio de transporte.
Exemplo Histórico: APIs Baseadas em XML-RPC
- No início dos anos 2000, APIs baseadas em XML-RPC (Remote Procedure Call sobre XML) começaram a organizar os dados em URLs específicas, mas ainda usavam um único método HTTP (normalmente POST) para todas as operações.
- Um exemplo clássico foi o Movable Type API (2001), uma das primeiras APIs para blogs, que permitia a publicação de posts usando XML-RPC.
- Todas as requisições eram enviadas para um único endpoint
/api
, com o corpo da requisição contendo instruções como:<methodCall> <methodName>getPost</methodName> <params> <param> <value><string>123</string></value> </param> </params> </methodCall>
Nível 2 - "Uso Correto de Verbos HTTP" (HTTP Verbs)
Aqui, a API começa a utilizar corretamente os métodos HTTP (GET, POST, PUT, DELETE, PATCH). Isso significa que as operações são realizadas de maneira semântica:
- GET → Para leitura de dados
- POST → Para criação de dados
- PUT → Para substituição completa de um recurso
- PATCH → Para atualização parcial de um recurso
- DELETE → Para remoção de um recurso
A partir deste nível, a API se torna mais intuitiva e previsível, pois os clientes podem deduzir como interagir com ela sem precisar consultar documentação detalhada.
Exemplo Histórico: APIs RESTful do Twitter e Facebook
- Em 2006, o Twitter lançou uma API RESTful que adotava corretamente os verbos HTTP.
- Exemplo real:
- Para obter um tweet:
GET /tweets/12345
- Para deletar um tweet:
DELETE /tweets/12345
- Para postar um novo tweet:
POST /tweets
- Para obter um tweet:
- Essa API foi um marco na adoção de REST, e influenciou APIs de redes sociais como Facebook e Instagram.
- Comparação: Enquanto a API REST do Twitter era nível 2, a API SOAP de serviços bancários ainda operava no nível 0 ou 1, sem uso correto dos verbos HTTP.
Nível 3 - "HATEOAS" (Hypermedia as the Engine of Application State)
O nível mais avançado da maturidade REST adiciona um conceito chamado HATEOAS (Hypermedia as the Engine of Application State). Isso significa que a API não apenas expõe recursos, mas também fornece informações sobre como interagir com esses recursos dinamicamente.
- Em um sistema HATEOAS, cada resposta da API contém links para ações relacionadas.
- Isso permite que os clientes descubram funcionalidades sem depender de documentações rígidas.
Exemplo Histórico: API REST da Amazon (2011)
- Em 2011, a Amazon implementou uma versão avançada de sua API de e-commerce usando HATEOAS.
- Exemplo de resposta JSON:
{ "id": 12345, "nome": "Produto X", "preco": 99.99, "_links": { "comprar": { "href": "/carrinho/12345", "method": "POST" }, "avaliacoes": { "href": "/produtos/12345/avaliacoes", "method": "GET" } } }
- Aqui, o cliente não precisa saber previamente que
/carrinho/12345
é o endpoint para adicionar um item ao carrinho. O próprio servidor fornece essa informação. - Impacto: Essa abordagem começou a ser adotada por APIs de grandes plataformas como PayPal e Stripe, permitindo descoberta dinâmica de ações e reduzindo a necessidade de hardcoding nos clientes.
Ou seja...
O Modelo de Maturidade de Richardson nos ajuda a avaliar o quão RESTful uma API realmente é. Ele permite entender como a evolução das APIs foi impulsionada pela necessidade de escalabilidade, flexibilidade e simplicidade.
Nível | Característica | Exemplo Histórico |
---|---|---|
0 | Apenas HTTP como transporte (SOAP/XML-RPC) | APIs SOAP do governo dos EUA (anos 2000) |
1 | Recursos identificáveis por URL, mas sem uso adequado de métodos HTTP | XML-RPC do Movable Type (2001) |
2 | Uso correto dos métodos HTTP (GET, POST, PUT, DELETE, PATCH) | API REST do Twitter (2006) |
3 | HATEOAS, permitindo descoberta dinâmica | API REST da Amazon (2011) |
Hoje, a maioria das APIs modernas opera no nível 2, mas algumas empresas estão adotando nível 3 com HATEOAS, especialmente em ambientes complexos, como microserviços.
1.7 Comparação: REST vs SOAP vs RPC
REST vs SOAP (Simple Object Access Protocol)
Característica | REST | SOAP |
---|---|---|
Protocolo | HTTP | HTTP, SMTP, TCP |
Formato de Dados | JSON, XML | Apenas XML |
Facilidade de Uso | Simples e flexível | Estruturado e verboso |
Desempenho | Alto (leve) | Baixo (mais pesado) |
Escalabilidade | Fácil de escalar | Difícil de escalar |
Cache | Sim | Não |
Segurança | Depende da implementação (HTTPS, JWT, OAuth) | Segurança robusta integrada (WS-Security) |
Utilização | Aplicações web modernas, microserviços | Sistemas bancários, integração empresarial |
- SOAP é usado em aplicações críticas (bancos, pagamentos) e sistemas legados.
- REST é mais leve e flexível, sendo mais popular para aplicações web e microsserviços.
REST vs RPC (Remote Procedure Call)
Característica | REST | RPC |
---|---|---|
Conceito | Manipulação de recursos | Chamada direta de funções remotas |
Formato de Comunicação | JSON, XML | Pode ser binário (gRPC, Thrift) ou JSON |
Independência de Plataforma | Alta | Média (pode exigir bibliotecas específicas) |
Simplicidade | Simples, segue HTTP | Pode ser complexo |
Utilização | Aplicações web, microsserviços | Comunicação de alto desempenho entre serviços |
- RPC é usado quando a comunicação precisa ser rápida e eficiente (ex.: gRPC no Google).
- REST é mais intuitivo e fácil de usar para integração entre sistemas independentes.
1.8 Boas Práticas ao Criar APIs REST 📌
Criar uma API REST eficiente, intuitiva e escalável vai além de simplesmente expor endpoints HTTP. Seguir boas práticas melhora a usabilidade, manutenção, segurança e desempenho da API, tornando-a mais fácil de integrar com outras aplicações. A seguir, apresentamos algumas diretrizes fundamentais para a construção de APIs REST profissionais:
1️. Use Substantivos nos Endpoints e Evite Verbos
Os endpoints representam recursos, portanto, devem ser nomes de substantivos no plural, e não ações ou verbos.
✅ Certo:
GET /contacts → Obtém todos os contatos
GET /contacts/{id} → Obtém um contato específico
POST /contacts → Cria um novo contato
DELETE /contacts/{id} → Remove um contato
❌ Errado:
GET /getContacts → Não precisa do verbo "get", pois o método HTTP já indica a ação
POST /createContact → O verbo "create" é desnecessário, pois o método POST já sugere criação
DELETE /removeContact → O verbo "remove" também é desnecessário
💡 Regra geral: O método HTTP já indica a ação (GET para buscar, POST para criar, DELETE para remover, etc.), então o endpoint deve apenas representar o recurso.
2️. Use os Códigos de Status HTTP Corretamente
Os códigos de status HTTP ajudam o cliente da API a entender o resultado da requisição. Usar códigos corretos torna a API mais intuitiva e facilita a depuração.
Abaixo vamos apresentar alguns dos principais códigos de Status HTTP. Para mais informações, consulte o site https://http.cat/ (sugestão da Caroliny!).
✅ Principais códigos de status HTTP:
Código | Significado | Quando Usar? |
---|---|---|
200 OK | Sucesso | Quando uma requisição GET, PUT ou DELETE for bem-sucedida |
201 Created | Recurso Criado | Quando um novo recurso é criado via POST |
204 No Content | Sem Conteúdo | Quando um recurso é excluído com sucesso |
400 Bad Request | Requisição Inválida | Quando os dados enviados são inválidos |
401 Unauthorized | Não Autenticado | Quando o usuário não está autenticado |
403 Forbidden | Acesso Negado | Quando o usuário não tem permissão para acessar o recurso |
404 Not Found | Recurso Não Encontrado | Quando o recurso solicitado não existe |
409 Conflict | Conflito | Quando há um conflito de dados (ex.: tentativa de criar um registro duplicado) |
500 Internal Server Error | Erro Interno | Quando ocorre um erro inesperado no servidor |
💡 Exemplo Prático: Se um usuário tenta buscar um contato que não existe:
❌ Errado:
{
"message": "Contato não encontrado"
}
✅ Certo (Retorna o código 404):
HTTP/1.1 404 Not Found
{
"error": "Contato não encontrado"
}
3️. Evite Expor Detalhes Internos da API
Nunca retorne informações sensíveis sobre a API ou stack traces detalhadas em respostas de erro. Isso pode expor vulnerabilidades para possíveis ataques.
❌ Errado (Expondo detalhes internos):
{
"error": "java.lang.NullPointerException at ContactService.java:34"
}
✅ Certo (Mensagem amigável e segura):
{
"error": "Erro ao processar a requisição. Tente novamente mais tarde."
}
💡 Dica: Sempre trate exceções e retorne mensagens amigáveis para o cliente, sem expor detalhes da implementação.
4️. Implemente Paginação em Grandes Listas
Quando a API retorna uma grande quantidade de dados, a paginação evita sobrecarregar o servidor e melhora o desempenho.
✅ Exemplo de Paginação:
GET /contacts?page=1&size=10
✅ Resposta JSON com metadados de paginação:
{
"data": [
{ "id": 1, "nome": "João" },
{ "id": 2, "nome": "Maria" }
],
"page": 1,
"size": 10,
"totalPages": 5,
"totalItems": 50
}
💡 Dica: Utilize frameworks como o Spring Data Pageable para implementar paginação de forma eficiente.
5️. Mantenha a API Intuitiva e Consistente
Uma API bem projetada deve ser fácil de usar, padronizada e previsível, permitindo que os desenvolvedores consigam integrá-la sem precisar consultar constantemente a documentação.
✅ Boas práticas para manter a API intuitiva:
- Use convenções de nomenclatura consistentes em todos os endpoints.
- Padronize os formatos de resposta JSON, garantindo que todas as respostas sigam a mesma estrutura.
- Retorne mensagens de erro claras, explicando o problema e como resolvê-lo.
- Forneça documentação da API com exemplos de uso.
6️. Use Versionamento na API
Com o tempo, APIs evoluem e podem quebrar compatibilidade com versões antigas. Para evitar problemas, sempre versione a API.
✅ Exemplo de versionamento:
GET /v1/contacts → Versão 1
GET /v2/contacts → Versão 2
💡 Dica: Se a API passar por mudanças grandes, mantenha versões anteriores disponíveis para evitar que clientes antigos quebrem.
7️. Documente sua API de Forma Clara
A documentação é essencial para que outros desenvolvedores entendam como usar sua API. Utilize ferramentas como:
- Swagger/OpenAPI → Gera documentação interativa automaticamente.
- Postman → Permite criar coleções de requisições de API documentadas.
- Redoc → Gera documentação HTML a partir do OpenAPI.
✅ Exemplo de documentação com Swagger:
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/contacts")
public class ContactController {
@Operation(summary = "Lista todos os contatos", description = "Retorna uma lista paginada de contatos")
@GetMapping
public List<Contact> getAllContacts() {
return contactRepository.findAll();
}
}
Seguir essas boas práticas ao criar APIs REST melhora a usabilidade, segurança e desempenho da aplicação. Implementar um design padronizado facilita a adoção da API por outros desenvolvedores e reduz a necessidade de documentação extensiva.
Checklist de Boas Práticas:
✅ Nomes de endpoints no plural e sem verbos
✅ Uso correto dos métodos HTTP e códigos
de status
✅ Mensagens de erro claras e sem detalhes internos
✅
Paginação para grandes listas
✅ API intuitiva e fácil de entender
✅
Versionamento para evitar quebra de compatibilidade
✅ Documentação clara e bem
estruturada
Aplique essas práticas para construir APIS REST mais robustas, escaláveis e fáceis de usar! 🚀
1.9 Conclusão
As APIs REST se tornaram o padrão para integração de sistemas modernos devido à sua simplicidade, flexibilidade e eficiência. Elas permitem que diferentes aplicações, independentemente da tecnologia utilizada, possam se comunicar utilizando os princípios da web.
Vamos colocar as mãos na massa e construir uma API REST com Spring Boot, explorando como criar, expor e manipular recursos de forma eficiente. Nosso objetivo é compreender os fundamentos e boas práticas do desenvolvimento de APIs REST para aplicações reais.
2. Introdução ao Spring Boot
O Spring Boot é um framework que facilita a criação de aplicativos em Java, fornecendo uma estrutura de projeto pré-configurada que agiliza o desenvolvimento.
O Spring Boot segue o princípio de Convention Over Configuration (Convenção sobre Configuração), que é um princípio de desenvolvimento que reduz a necessidade de configurações explícitas, fornecendo valores e comportamentos padrão sensíveis. O desenvolvedor só precisa configurar explicitamente algo quando deseja modificar o comportamento padrão.
Isso significa que ele vem com configurações padrão inteligentes que permitem aos desenvolvedores começarem rapidamente sem precisar definir manualmente cada detalhe da aplicação, o que elimina grande parte da configuração manual tradicional do Spring, permitindo que o desenvolvedor foque mais na lógica de negócio.
Sim, a explicação está clara e bem estruturada! Ela destaca os principais pontos sobre o Spring Boot e seu uso do princípio Convention Over Configuration de forma objetiva. No entanto, se quiser torná-la ainda mais acessível, você pode adicionar um exemplo rápido para ilustrar a ideia.
📌 Exemplo prático:
No Spring tradicional, para configurar um banco de dados, seria
necessário definir manualmente um DataSource, gerenciar transações e configurar o Hibernate.
Com o Spring Boot, basta adicionar as dependências necessárias e incluir algumas linhas no
application.properties
:
spring.datasource.url=jdbc:mysql://localhost:3306/meubanco spring.datasource.username=root spring.datasource.password=senha
Ou seja, o Spring Boot detecta automaticamente o banco de dados e configura o Hibernate sem necessidade de configurações adicionais.
Criando o Projeto Spring Boot
Antes de iniciarmos a implementação da nossa API REST, precisamos criar o projeto Spring Boot. Podemos fazer isso de diversas maneiras, mas utilizaremos a abordagem mais prática: o Spring Initializr.
🔹 Criando o Projeto com Spring Initializr
O Spring Initializr é uma ferramenta online que permite configurar e gerar rapidamente um projeto Spring Boot com as dependências necessárias.
Passo a passo para criar o projeto:
-
Acesse o Spring Initializr
- Acesse https://start.spring.io/
-
Configure o projeto
- Project: Maven (ou Gradle, se preferir)
- Language: Java
- Spring Boot Version: Escolha a versão mais recente estável
- Group:
br.ifsp
- Artifact:
contacts-api
- Name:
contacts-api
- Description:
API para gerenciamento de contatos
- Package Name:
br.ifsp.contacts
- Packaging: Jar
- Java Version: 11 ou superior (recomendado)
-
Adicione as dependências essenciais
- Spring Web → Para criar a API REST
- Spring Boot DevTools → Para recarregamento automático durante o desenvolvimento
- Spring Data JPA → Para interação com banco de dados
- H2 Database → Banco de dados em memória para testes
-
Gerar e baixar o projeto
- Clique em "Generate" para baixar o projeto
.zip
- Extraia o
.zip
em uma pasta de sua preferência.
- Clique em "Generate" para baixar o projeto
🔹 Importando o Projeto na IDE
Após baixar e extrair o projeto, é hora de importá-lo para uma IDE (como IntelliJ IDEA, Eclipse ou VS Code com extensão Java).
Se estiver usando IntelliJ IDEA:
- Abra o IntelliJ IDEA.
- Clique em File > Open.
- Selecione a pasta do projeto (
contacts-api
) e clique em Open. - Aguarde o Maven ou Gradle baixar as dependências automaticamente.
Se estiver usando Eclipse:
- Vá até File > Import.
- Escolha Existing Maven Projects.
- Selecione a pasta onde extraiu o projeto.
- Clique em Finish e aguarde a configuração.
🔹 Rodando o Projeto pela Primeira Vez
Agora que temos o projeto configurado, podemos rodá-lo pela primeira vez.
- Abra o terminal na pasta do projeto.
- Se estiver usando Maven, execute:
Se estiver usando Gradle, execute:mvn spring-boot:run
./gradlew bootRun
- Aguarde até que a aplicação inicie. Se tudo estiver correto, você verá algo como:
Tomcat started on port(s): 8080 (http)
Agora sua API está rodando localmente na porta 8080 e pronta para receber requisições! 🎉
Caso queira testar se está funcionando, abra o navegador e acesse:
http://localhost:8080
A princípio, receberá uma resposta Whitelabel Error Page
, pois ainda não criamos nenhuma rota. Nas
próximas etapas, adicionaremos os endpoints REST.
2.1 Estrutura do Projeto
Ao criar um projeto com o Spring Boot, é comum utilizar o padrão de pastas do Maven, mesmo que o seu build tool seja o Maven ou Gradle. Essa estrutura fica geralmente assim:
.
├── src
│ ├── main
│ │ ├── java
│ │ │ └── br
│ │ │ └── ifsp
│ │ │ └── contacts
│ │ │ ├── ContactsApplication.java
│ │ │ ├── controller
│ │ │ │ └── ContactController.java
│ │ │ ├── model
│ │ │ │ └── Contact.java
│ │ │ └── repository
│ │ │ └── ContactRepository.java
│ │ └── resources
│ │ └── application.properties
│ └── test
│ └── java
└── pom.xml (ou build.gradle)
A seguir, veremos cada arquivo principal e as explicações associadas.
2.2 Arquivo de Inicialização: ContactsApplication.java
Este é o ponto de entrada da aplicação Spring Boot. É nele que colocamos a anotação
@SpringBootApplication
, que habilita diversas configurações automáticas:
package br.ifsp.contacts;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Classe principal da nossa aplicação Spring Boot.
*
* A anotação @SpringBootApplication habilita as configurações
* automáticas do Spring (auto-configuration) e também indica
* que esta é a classe que deve ser executada para iniciar
* a aplicação.
*/
@SpringBootApplication
public class ContactsApplication {
public static void main(String[] args) {
// Método main: ponto de entrada de uma aplicação Java.
// SpringApplication.run() inicia a aplicação Spring Boot.
SpringApplication.run(ContactsApplication.class, args);
}
}
Explicação:
@SpringBootApplication
é uma anotação que combina diversas funcionalidades, como:@Configuration
: para permitir configurações na aplicação.@EnableAutoConfiguration
: faz com que o Spring Boot configure automaticamente componentes relevantes, de acordo com o que encontra no classpath do projeto.@ComponentScan
: faz com que o Spring procure automaticamente classes anotadas como componentes dentro do mesmo pacote ou em pacotes filhos.
Quando executamos o método main
, o Spring Boot levanta um servidor embutido (por
padrão, o Tomcat) e passa a escutar as requisições HTTP.
2.3 Modelo de Dados: Contact.java
Para representar cada contato, precisamos de uma classe que contenha seus atributos. Chamamos essa classe de modelo, ou entidade, quando falamos de persistência de dados.
package br.ifsp.contacts.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
* Classe que representa o modelo de dados para um Contato.
*
* @Entity indica que este objeto será mapeado para uma tabela
* no banco de dados (em cenários de persistência com JPA).
*/
@Entity
public class Contact {
/**
* @Id indica que este campo é a chave primária (primary key) da entidade.
* @GeneratedValue permite que o banco de dados (ou o provedor JPA)
* gere automaticamente um valor único para cada novo registro.
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nome;
private String telefone;
private String email;
// Construtor vazio exigido pelo JPA
public Contact() {}
// Construtor para facilitar a criação de objetos
public Contact(String nome, String telefone, String email) {
this.nome = nome;
this.telefone = telefone;
this.email = email;
}
// Getters e Setters
public Long getId() {
return id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getTelefone() {
return telefone;
}
public void setTelefone(String telefone) {
this.telefone = telefone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Explicação:
@Entity
diz ao Spring/Data JPA (ou outro provedor de JPA) que esta classe é uma entidade que será mapeada para uma tabela no banco de dados.@Id
define o identificador único do registro.@GeneratedValue(strategy = GenerationType.IDENTITY)
faz com que o valor do ID seja gerado automaticamente (por exemplo, auto-increment em bancos relacionais).Long id
,String nome
,String telefone
eString email
são os campos que vamos manipular.
Mesmo que ainda não estejamos aprofundando no uso de banco de dados real, este exemplo já está preparado para persistência caso seja configurado um banco H2 ou outro SGBD.
2.4 Repositório de Dados: ContactRepository.java
O repositório é responsável por realizar as operações de acesso aos dados (criar, ler, atualizar, excluir).
Vamos utilizar a interface JpaRepository
do Spring Data JPA, que já oferece as
implementações básicas de CRUD, bastando nós definirmos a interface corretamente.
package br.ifsp.contacts.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import br.ifsp.contacts.model.Contact;
/**
* Esta interface extende JpaRepository, que nos fornece métodos prontos
* para acessar e manipular dados no banco de dados. Basta especificar
* a classe de entidade (Contact) e o tipo da chave primária (Long).
*/
public interface ContactRepository extends JpaRepository<Contact, Long> {
// Podemos adicionar métodos personalizados se necessário.
}
Explicação:
- Ao estender
JpaRepository<Contact, Long>
, nós ganhamos de forma automática diversos métodos como:save()
- para inserir ou atualizar um contatofindById()
- para buscar contato por IDfindAll()
- para buscar todos os contatosdeleteById()
- para deletar contato por ID
- O
ContactRepository
já está pronto para ser injetado em outras camadas da aplicação (como na Controller).
2.5 Controlador (Controller): ContactController.java
O controlador é a classe que “escuta” as requisições HTTP e define como o sistema vai
responder. Nele, utilizamos anotações como @RestController
(que indica um controller REST) e
@RequestMapping
(para definir o caminho base dos endpoints, também chamados de “URIs” ou “rotas”).
package br.ifsp.contacts.controller;
import br.ifsp.contacts.model.Contact;
import br.ifsp.contacts.repository.ContactRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* Classe responsável por mapear as rotas/endpoints relacionados
* aos contatos. Cada método abaixo corresponde a uma operação
* em nosso sistema.
*
* @RestController: Indica que esta classe é um controlador
* responsável por responder requisições REST.
* @RequestMapping("/api/contacts"): Indica o caminho base.
*/
@RestController
@RequestMapping("/api/contacts")
public class ContactController {
/**
* @Autowired permite que o Spring "injete" automaticamente
* uma instância de ContactRepository aqui,
* sem que precisemos criar manualmente.
*/
@Autowired
private ContactRepository contactRepository;
/**
* Método para obter todos os contatos.
*
* @GetMapping indica que este método vai responder a chamadas HTTP GET.
* Exemplo de acesso: GET /api/contacts
*/
@GetMapping
public List<Contact> getAllContacts() {
return contactRepository.findAll();
}
/**
* Método para obter um contato específico pelo seu ID.
*
* @PathVariable "amarra" a variável {id} da URL
* ao parâmetro do método.
* Exemplo de acesso: GET /api/contacts/1
*/
@GetMapping("/{id}")
public Contact getContactById(@PathVariable Long id) {
// findById retorna um Optional, então usamos orElseThrow
return contactRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Contato não encontrado: " + id));
}
/**
* Método para criar um novo contato.
*
* @PostMapping indica que este método responde a chamadas HTTP POST.
* @RequestBody indica que o objeto Contact será preenchido
* com os dados JSON enviados no corpo da requisição.
*/
@PostMapping
public Contact createContact(@RequestBody Contact contact) {
return contactRepository.save(contact);
}
/**
* Método para atualizar um contato existente.
*
* @PutMapping indica que este método responde a chamadas HTTP PUT.
* Exemplo de acesso: PUT /api/contacts/1
*/
@PutMapping("/{id}")
public Contact updateContact(@PathVariable Long id, @RequestBody Contact updatedContact) {
// Buscar o contato existente
Contact existingContact = contactRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Contato não encontrado: " + id));
// Atualizar os campos
existingContact.setNome(updatedContact.getNome());
existingContact.setTelefone(updatedContact.getTelefone());
existingContact.setEmail(updatedContact.getEmail());
// Salvar alterações
return contactRepository.save(existingContact);
}
/**
* Método para excluir um contato pelo ID.
*
* @DeleteMapping indica que este método responde a chamadas HTTP DELETE.
* Exemplo de acesso: DELETE /api/contacts/1
*/
@DeleteMapping("/{id}")
public void deleteContact(@PathVariable Long id) {
contactRepository.deleteById(id);
}
}
Explicação:
-
@RestController
:- Indica que esta classe processa requisições REST (ou seja, retorna dados em JSON ou outro formato) e não retorna diretamente páginas HTML.
-
@RequestMapping("/api/contacts")
:- Define que todos os métodos dentro deste controller estarão acessíveis a partir de URIs que começam com
/api/contacts
. Por exemplo, se o método for anotado com@GetMapping
, isso viraráGET /api/contacts
.
- Define que todos os métodos dentro deste controller estarão acessíveis a partir de URIs que começam com
-
Métodos HTTP:
@GetMapping
→ Método GET do protocolo HTTP. Para obter (ler) dados.@PostMapping
→ Método POST do protocolo HTTP. Para criar (inserir) dados.@PutMapping
→ Método PUT do protocolo HTTP. Para atualizar (modificar) dados.@DeleteMapping
→ Método DELETE do protocolo HTTP. Para excluir dados.
-
@PathVariable
:- Indica que o valor do parâmetro
id
virá diretamente do segmento correspondente na URL. Por exemplo, ao acessarGET /api/contacts/10
, o valor10
será atribuído ao parâmetroid
.
- Indica que o valor do parâmetro
-
@RequestBody
:- Indica que o parâmetro do método (
Contact contact
) deve ser populado com o corpo da requisição. Em uma chamada POST com corpo JSON, os camposnome
,telefone
,email
(por exemplo) serão convertidos em um objetoContact
.
- Indica que o parâmetro do método (
-
Injeção de Dependência (
@Autowired
):- O Spring cria e gerencia o objeto
ContactRepository
. Ao colocar@Autowired
, estamos dizendo ao Spring para injetar nesse campo a instância do nosso repositório, economizando a tarefa de instanciá-lo manualmente.
- O Spring cria e gerencia o objeto
2.6 Arquivo de Configuração: application.properties
Caso quiséssemos usar o banco H2 em memória para testes ou configurações adicionais, poderíamos adicionar
alguns parâmetros no application.properties
. Por exemplo:
spring.datasource.url=jdbc:h2:mem:contacts_db
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true
Explicação:
spring.datasource.url
espring.datasource.driverClassName
definem o local do banco e o driver de conexão.spring.jpa.hibernate.ddl-auto=update
faz com que a tabela seja criada/atualizada automaticamente ao iniciar a aplicação, conforme as entidades definidas.spring.h2.console.enabled=true
habilita um console web para ver e manipular dados do banco (acessível em/h2-console
quando a aplicação está rodando).
Se não quisermos usar H2, ainda assim podemos manter o projeto como está, pois o Spring Boot, por padrão, tentará criar um banco em memória se não for configurado outro banco real.
2.7 Build e Execução
Usando Maven
Se estivermos utilizando Maven, teremos um arquivo pom.xml
na raiz do projeto. Ele conterá, entre
outras coisas, as dependências:
<dependencies>
<!-- Dependência do Spring Web, para criar a API REST -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Dependência do Spring Data JPA, para acesso a dados -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Dependência para banco H2 em memória (opcional) -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>
Para rodar, podemos simplesmente executar:
mvn spring-boot:run
ou, se gerarmos um .jar
, podemos rodar:
java -jar target/contacts-0.0.1-SNAPSHOT.jar
Usando Gradle
Caso nosso projeto fosse em Gradle, teríamos um arquivo build.gradle
. O conteúdo
principal para as dependências seria algo como:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.h2database:h2'
}
Para iniciar a aplicação:
./gradlew bootRun
Maven vs. Gradle: Comparação e Diferenças
Ao desenvolver aplicações com Spring Boot, é necessário um gerenciador de dependências e build para automatizar tarefas como compilação, empacotamento, testes e execução do projeto. Os dois principais gerenciadores no ecossistema Java são Maven e Gradle.
Estrutura e Configuração
- Maven utiliza um arquivo XML (
pom.xml
), que define as dependências e configurações do projeto de maneira declarativa. - Gradle usa arquivos baseados em Groovy ou Kotlin (
build.gradle
oubuild.gradle.kts
).
Desempenho e Eficiência
- Gradle é mais rápido que Maven, pois utiliza builds incrementais e cache de tarefas, evitando a recompilação de código desnecessário.
- Maven sempre executa as tarefas do zero, tornando o build mais previsível, porém mais lento.
Sintaxe e Facilidade de Uso
- Maven tem uma sintaxe rígida e baseada em XML, o que pode gerar arquivos longos e verbosos.
- Gradle tem uma sintaxe mais concisa e expressiva, facilitando a configuração de builds complexos.
Popularidade e Comunidade
- Maven tem uma comunidade maior e uma adoção mais ampla, sendo o padrão em muitos projetos Java.
- Gradle tem ganhado espaço, especialmente em projetos modernos, e é amplamente usado no desenvolvimento Android.
Ou seja...
- Se você busca padronização e estabilidade, Maven é uma excelente escolha.
- Se precisa de builds mais rápidos e configuráveis, Gradle pode ser a melhor opção.
Ambas as ferramentas são compatíveis com Spring Boot, então a escolha depende das necessidades do projeto e do conhecimento prévio da equipe.
Ao longo da disciplina utilizaremos o Maven como ferramenta padrão, dada sua maior popularidade.
2.8 Testando a API
Ao desenvolver uma API REST, é essencial testar suas funcionalidades para verificar se os endpoints estão respondendo corretamente. Para isso, utilizamos clients de API, que permitem enviar requisições HTTP e visualizar as respostas do servidor. Dentre os mais populares, temos as seguintes opções.
Postman 📨
O Postman é um dos clientes de API mais populares e oferece uma interface
gráfica para:
✅ Enviar requisições GET, POST, PUT, PATCH, DELETE com facilidade.
✅
Adicionar headers, parâmetros e autenticação às requisições.
✅ Salvar coleções de
requisições para testes automatizados.
✅ Simular corpos JSON e XML no envio de
dados.
👉 Exemplo:
- Abra o Postman e crie uma nova requisição.
- Escolha GET e insira
http://localhost:8080/api/contacts
. - Clique em Send e visualize a resposta JSON da API.
💡 O Postman também suporta testes automatizados e integração com CI/CD.
Insomnia 🌙
O Insomnia é uma alternativa ao Postman, mais leve e focada na simplicidade. Ele permite:
✅
Criar e organizar requisições de forma intuitiva.
✅ Testar APIs REST, GraphQL e WebSockets.
✅ Gerenciar
variáveis de ambiente para diferentes contextos (desenvolvimento, produção).
💡 É recomendado para quem busca uma experiência mais fluida e rápida, sem tantas funcionalidades avançadas.
cURL 🖥️
O cURL é uma ferramenta de linha de comando para testar APIs diretamente no terminal. É útil para desenvolvedores que preferem scripts e automação.
👉 Exemplo de requisição GET com cURL:
curl -X GET http://localhost:8080/api/contacts
👉 Exemplo de requisição POST com JSON:
curl -X POST http://localhost:8080/api/contacts \
-H "Content-Type: application/json" \
-d '{"nome": "Maria", "telefone": "9999-9999", "email": "maria@email.com"}'
💡 cURL é embutido no Linux e macOS e pode ser usado em scripts para testes automatizados.
Alternativas e Ferramentas Adicionais
- Hoppscotch → Cliente de API online e gratuito, semelhante ao Postman.
- Thunder Client → Extensão do VS Code para testar APIs REST sem sair do editor.
- HTTPie → Alternativa ao cURL com saída mais legível.
Independentemente da ferramenta, testar a API é fundamental para garantir que os endpoints funcionam conforme esperado! 🚀
Com o client em mãos, vamos ao teste da API!
Depois que a aplicação estiver em execução (por padrão, na porta 8080), podemos testar as rotas usando alguma das ferramentas descritas acima. Ao longo da disciplina utilizaremos principalmente o Postman.
-
Criar contato (POST)
POST /api/contacts Body (JSON): { "nome": "João da Silva", "telefone": "9999-9999", "email": "joao@email.com" }
- Resposta: Objeto JSON do contato criado, incluindo o
id
atribuído.
- Resposta: Objeto JSON do contato criado, incluindo o
-
Obter todos os contatos (GET)
GET /api/contacts
- Resposta: Lista de contatos em formato JSON.
-
Obter contato específico (GET)
GET /api/contacts/1
- Resposta: Objeto JSON com o contato de ID 1 (caso exista).
-
Atualizar contato (PUT)
PUT /api/contacts/1 Body (JSON): { "nome": "Maria da Silva", "telefone": "8888-8888", "email": "maria@email.com" }
- Resposta: Objeto JSON com o contato atualizado.
-
Excluir contato (DELETE)
DELETE /api/contacts/1
- Resposta: Sem corpo (status HTTP 200 ou 204).
2.9 Recapitulando
Neste projeto, apresentamos:
- O que é uma API REST e como o Spring Boot facilita sua criação.
- Os principais verbos HTTP (GET, POST, PUT, DELETE) e como eles se relacionam com operações de leitura, criação, atualização e exclusão de dados.
- Como estruturar um projeto Spring Boot com:
- Classe principal (
ContactsApplication
) - Entidade de modelo (
Contact
) - Repositório de dados (
ContactRepository
) - Controlador REST (
ContactController
) - Configurações no
application.properties
e dependências nopom.xml
oubuild.gradle
.
- Classe principal (
Essa base serve para, gradualmente, adicionar mais funcionalidades, como:
- Validações nos campos de contato.
- Tratamento de exceções customizadas.
- Autenticação e autorização (segurança).
- Integração com bancos de dados reais ou outros serviços.
O que aprendemos até aqui?
✅ O que são APIs REST e seus princípios fundamentais.
✅ Os métodos HTTP (GET, POST,
PUT, PATCH, DELETE) e seu uso correto.
✅ A importância da padronização e do modelo de
maturidade de Richardson.
✅ A estrutura de um projeto Spring Boot e como criar uma API
básica.
✅ Como testar APIs usando ferramentas como Postman, Insomnia e cURL.
Por enquanto, nossa aplicação já exemplifica o essencial do desenvolvimento de uma API REST com o Spring Boot.
Sigam este passo-a-passo e executem o código-fonte como ponto de partida para os exercícios posteriores.
3. Conclusão e Próximos Passos
Nesta aula vimos que uma API REST segue um conjunto de padrões baseados no protocolo HTTP, permitindo a comunicação entre sistemas de maneira padronizada, previsível e escalável. Para garantir que uma API seja realmente RESTful, entendemos a importância do modelo de maturidade de Richardson, que nos ajuda a avaliar a conformidade de uma API com os princípios REST.
Além disso, iniciamos a introdução ao Spring Boot, uma tecnologia que simplifica o desenvolvimento de aplicações Java, eliminando a necessidade de configurações manuais complexas e permitindo que possamos rapidamente criar e expor endpoints RESTful. Aprendemos a estrutura de um projeto Spring Boot e implementamos os principais componentes necessários para a construção de uma API de lista de contatos.
Nas próximas aulas avançaremos na construção de APIs mais robustas e completas. Trabalharemos com novos conceitos essenciais para um desenvolvimento profissional, incluindo:
🔹 Validações e Tratamento de Erros: Garantindo que nossa API retorne respostas consistentes e
evite entradas inválidas.
🔹 Persistência e Banco de Dados: Integração da API com um banco
de dados real para armazenar os contatos de forma permanente.
🔹 Autenticação e Segurança:
Protegendo a API com mecanismos de autenticação, como OAuth e JWT.
🔹 Boas Práticas e
Documentação: Como tornar nossa API mais compreensível e fácil de usar para outros desenvolvedores.
Antes disso, entretanto, é necessário solidificar os conteúdos vistos até aqui.
4. Exercícios
Os exercícios a seguir têm como objetivo reforçar os conceitos apresentados na aula e permitir que você pratique o desenvolvimento de APIs REST com Spring Boot.
📌 Instruções:
- Os exercícios devem ser entregues no Moodle dentro do prazo estipulado.
- Sempre comente o código explicando as principais partes da implementação.
- Utilize Postman, Insomnia ou cURL para testar os endpoints criados.
- O código-fonte deve ser enviado em um repositório no GitHub (ou em anexo no Moodle, se preferir).
1️⃣ Exercício 1 - Criando um Novo Endpoint GET
Crie um novo endpoint GET em ContactController
que permita buscar
contatos pelo nome.
📌 Requisitos:
- O método deve receber o nome como um parâmetro de URL
(
/api/contacts/search?name=João
). - O método deve retornar uma lista de contatos que correspondam ao nome fornecido.
- Caso nenhum contato seja encontrado, retorne uma lista vazia.
📌 Dicas:
- Você pode precisar modificar a interface
ContactRepository
para adicionar um método de busca personalizada.
📝 Saída esperada (JSON):
[
{
"id": 1,
"nome": "João Silva",
"telefone": "9999-9999",
"email": "joao@email.com"
}
]
2️⃣ Exercício 2 - Implementando um Método PATCH
Adicione um novo método PATCH à API, permitindo que o usuário atualize apenas um ou mais campos de um contato, sem precisar enviar todos os dados.
📌 Requisitos:
- O método deve permitir alterar apenas os campos enviados na requisição.
- Se o campo não for enviado, o valor original deve ser mantido.
- Retorne o contato atualizado após a alteração.
- Caso o ID fornecido não exista, retorne um erro 404.
📌 Exemplo de chamada:
PATCH /api/contacts/1
{
"email": "novoemail@email.com"
}
📝 Saída esperada (JSON):
{
"id": 1,
"nome": "João Silva",
"telefone": "9999-9999",
"email": "novoemail@email.com"
}
3️⃣ Exercício 3 - REST e SOAP
Agora que você já conhece APIs REST, faça uma pesquisa sobre APIs SOAP e responda às perguntas abaixo com suas próprias palavras.
📌 Questões:
- Qual a principal diferença entre REST e SOAP?
- Em quais cenários SOAP ainda é utilizado?
- Quais são as vantagens e desvantagens de usar REST ao invés de SOAP?
- O que é WS-Security e como ele se compara à segurança em APIs REST?
- Explique o modelo de maturidade de Richardson.
- O que é GraphQL? Pesquisa e relacione com os conceitos vistos em aula.
1️⃣ Desafio 1 - Criando um Novo Modelo de Dados
Atualmente, nossa API gerencia apenas contatos. Agora, queremos adicionar um novo recurso: endereços.
📌 Tarefas:
- Crie uma nova entidade
Address
, com os seguintes atributos:id
(Long, auto-increment)rua
(String)cidade
(String)estado
(String)cep
(String)contactId
(Long) - Chave estrangeira referenciando um contato.
- Crie uma relação bidirecional entre contatos e endereços.
- Crie um repositório (
AddressRepository
) para gerenciar os endereços. - Implemente um novo
AddressController
para adicionar e recuperar endereços. - Crie uma rota GET
/api/contacts/{id}/addresses
para listar todos os endereços de um contato específico.
2️⃣ Desafio 2 - Melhorando a Validação dos Dados
Atualmente, nossa API aceita qualquer valor no cadastro de contatos. Precisamos garantir que os dados sejam válidos antes de inseri-los no banco de dados.
📌 Requisitos:
- Adicione validações à entidade
Contact
, utilizando a anotação@Valid
. - Implemente regras como:
- O campo
nome
não pode estar vazio. - O campo
email
deve ter um formato válido (@Email
). - O campo
telefone
deve ter no mínimo 8 e no máximo 15 caracteres.
- O campo
📌 Exemplo de resposta para entrada inválida:
Se tentarmos criar um contato com um telefone
inválido:
{
"nome": "Maria",
"telefone": "123",
"email": "maria@email.com"
}
A API deve retornar HTTP 400 e uma mensagem de erro:
{
"erro": "O telefone deve ter entre 8 e 15 caracteres"
}
📌 Instruções Finais
- ✅ Para os exercícios práticos (1 e 2) a entrega esperada é o código das novas rotas e prints das requisições no Postman ou Insomnia. Envie um link do GitHub ou um arquivo .zip com o código-fonte.
- ✅ Para o exercício teórico (3), envie um arquivo .pdf ou .txt com as respostas.
- ✅ A entrega dos desafios terá um prazo estendido até o Domingo posterior à data de entrega dos exercícios, também devendo ser entregue o código de implementação e os prints dos testes.
- ✅Teste todas as funcionalidades antes de enviar e garanta que o código está funcionando.