🔌 APIs - Interface de Programação de Aplicações
Conceitos, Arquitetura, Protocolos e Integração
1. O que é uma API?
API (Application Programming Interface) é um conjunto de regras que permite que diferentes sistemas se comuniquem e troquem informações de forma padronizada. Ela define como solicitações devem ser feitas, quais dados podem ser enviados e como as respostas serão estruturadas.
Ao usar uma API, o cliente faz uma requisição especificando o que deseja acessar. Essa requisição é enviada a um servidor, que processa o pedido e devolve uma resposta estruturada, normalmente no formato JSON ou XML.
Para acessar diferentes recursos dentro de um sistema, utilizam-se endpoints, que são como endereços específicos para cada funcionalidade. Por exemplo: /api/usuarios pode retornar uma lista de usuários.
As operações mais comuns em uma API seguem o padrão HTTP:
- GET: obter dados
- POST: enviar dados e criar novos registros
- PUT/PATCH: atualizar informações existentes
- DELETE: excluir dados
Muitas APIs exigem autenticação para garantir segurança. Isso pode ser feito com tokens, chaves de acesso ou protocolos como OAuth, protegendo informações e evitando acessos não autorizados.
APIs também podem ter limites de requisição (rate limits) para evitar sobrecarga, garantindo estabilidade e desempenho do sistema.
No mundo real, APIs permitem que aplicativos usem mapas, façam pagamentos, se conectem a redes sociais, enviem mensagens, consultem bancos de dados e muito mais, tornando o desenvolvimento mais rápido e eficiente.
Em resumo, uma API é a ponte que conecta sistemas, permitindo inovação sem precisar reinventar funcionalidades já existentes.
2. Conceitos Fundamentais
Cliente (Client)
- Função: Solicita dados ou funcionalidades
- Exemplos: Website, app mobile, outro backend
- Ação: Envia requisições HTTP
- Responsabilidade: Formatar dados corretamente
Servidor (Server)
- Função: Fornece dados ou funcionalidades
- Exemplos: Backend em Java, Node.js, Python
- Ação: Processa requisições e retorna respostas
- Responsabilidade: Validar e processar dados
3. Tipos de APIs
Existem diferentes tipos de APIs, cada uma com suas características, vantagens e casos de uso específicos.
REST API (Representational State Transfer):
// Mais popular e recomendada
// Usa URLs para representar recursos
// Métodos HTTP para operações (GET, POST, PUT, DELETE)
GET /api/usuarios // Listar todos
GET /api/usuarios/123 // Obter um específico
POST /api/usuarios // Criar novo
PUT /api/usuarios/123 // Atualizar
DELETE /api/usuarios/123 // Deletar
// Características:
// ✓ Simples e intuitiva
// ✓ Escalável
// ✓ Stateless (sem estado)
// ✓ Cacheable
SOAP (Simple Object Access Protocol):
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/">
<soap:Body>
<GetUsuario>
<id>123</id>
</GetUsuario>
</soap:Body>
</soap:Envelope>
// Características:
// ✓ Muito seguro
// ✓ Padrão W3C
// ✗ Pesado e complexo
// ✗ Menos usado atualmente (legado)
Webhook:
// A aplicação envia dados automaticamente quando algo acontece
// Orientada a eventos
// O servidor inicia a comunicação (não o cliente)
// Exemplo: Pagamento confirmado
POST https://seu-app.com/webhooks/pagamento
Content-Type: application/json
{
"evento": "pagamento_confirmado",
"id_pagamento": "pay_123",
"valor": 150.00,
"timestamp": "2025-10-29T14:30:00Z"
}
// Características:
// ✓ Orientado a eventos
// ✓ Tempo real
// ✓ Reduz polling
// ✗ Requer tratamento de erros robusto
4. Protocolo HTTP e Métodos
A maioria das APIs modernas usa HTTP como protocolo de transporte. Os principais métodos são:
Métodos HTTP e Operações:
// GET - Recuperar dados (READ)
GET /api/usuarios
GET /api/usuarios/123
Características: Seguro, Idempotente, Cacheável
// POST - Criar novo recurso (CREATE)
POST /api/usuarios
Body: { "nome": "João", "email": "joao@mail.com" }
Características: Não-idempotente, Pode ter efeitos colaterais
// PUT - Atualizar completamente (UPDATE)
PUT /api/usuarios/123
Body: { "nome": "João Silva", "email": "joao.silva@mail.com" }
Características: Idempotente, Substitui tudo
// PATCH - Atualizar parcialmente (PARTIAL UPDATE)
PATCH /api/usuarios/123
Body: { "nome": "João Silva" }
Características: Idempotente, Atualiza apenas campos enviados
// DELETE - Remover recurso (DELETE)
DELETE /api/usuarios/123
Características: Idempotente, Remove permanentemente
// HEAD - Como GET mas sem body
HEAD /api/usuarios
Características: Verifica disponibilidade sem dados
// OPTIONS - Descreve opções de comunicação
OPTIONS /api/usuarios
Características: Usado para CORS pré-flight
5. Códigos de Status HTTP
Status Codes - Categorizados:
// 2xx - SUCESSO ✓
200 OK - Requisição bem-sucedida
201 Created - Recurso criado com sucesso
204 No Content - Sucesso mas sem conteúdo no corpo
202 Accepted - Requisição aceita mas ainda processando
// 3xx - REDIRECIONAMENTO ↻
301 Moved Permanently - Mudou permanentemente
302 Found - Mudou temporariamente
304 Not Modified - Dados não alterados (use cache)
307 Temporary Redirect - Redireção temporária
// 4xx - ERRO DO CLIENTE ✗
400 Bad Request - Requisição inválida
401 Unauthorized - Autenticação necessária
403 Forbidden - Autenticado mas sem permissão
404 Not Found - Recurso não encontrado
409 Conflict - Conflito (ex: email duplicado)
429 Too Many Requests - Rate limit excedido
// 5xx - ERRO DO SERVIDOR ⚠
500 Internal Server Error - Erro interno no servidor
503 Service Unavailable - Serviço temporariamente indisponível
504 Gateway Timeout - Timeout na comunicação
6. Exemplo Prático: REST API com Spring Boot
Vamos criar uma REST API completa de gerenciamento de usuários em Java com Spring Boot.
Modelo (Entidade):
import javax.persistence.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "usuarios")
public class Usuario {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String nome;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
private String senha;
private boolean ativo = true;
@Column(name = "criado_em", updatable = false)
private LocalDateTime criadoEm = LocalDateTime.now();
@Column(name = "atualizado_em")
private LocalDateTime atualizadoEm;
}
Repositório (Data Access):
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UsuarioRepository extends JpaRepository {
Usuario findByEmail(String email);
boolean existsByEmail(String email);
}
Controlador (REST Endpoints):
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.time.LocalDateTime;
@RestController
@RequestMapping("/api/usuarios")
@CrossOrigin(origins = "*")
public class UsuarioController {
@Autowired
private UsuarioRepository usuarioRepository;
// GET - Listar todos
@GetMapping
public ResponseEntity> listarTodos() {
List usuarios = usuarioRepository.findAll();
return ResponseEntity.ok(usuarios);
}
// GET - Buscar por ID
@GetMapping("/{id}")
public ResponseEntity buscarPorId(@PathVariable Long id) {
return usuarioRepository.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
// POST - Criar novo usuário
@PostMapping
public ResponseEntity> criar(@RequestBody Usuario usuario) {
if (usuarioRepository.existsByEmail(usuario.getEmail())) {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body("Email já registrado");
}
usuario.setCriadoEm(LocalDateTime.now());
usuario.setAtualizado(LocalDateTime.now());
Usuario salvo = usuarioRepository.save(usuario);
return ResponseEntity.status(HttpStatus.CREATED).body(salvo);
}
// PUT - Atualizar completamente
@PutMapping("/{id}")
public ResponseEntity> atualizar(
@PathVariable Long id,
@RequestBody Usuario usuarioAtualizado) {
return usuarioRepository.findById(id)
.map(usuario -> {
usuario.setNome(usuarioAtualizado.getNome());
usuario.setEmail(usuarioAtualizado.getEmail());
usuario.setAtivo(usuarioAtualizado.isAtivo());
usuario.setAtualizadoEm(LocalDateTime.now());
Usuario salvo = usuarioRepository.save(usuario);
return ResponseEntity.ok(salvo);
})
.orElse(ResponseEntity.notFound().build());
}
// PATCH - Atualizar parcialmente
@PatchMapping("/{id}")
public ResponseEntity> atualizarParcial(
@PathVariable Long id,
@RequestBody Usuario usuarioAtualizado) {
return usuarioRepository.findById(id)
.map(usuario -> {
if (usuarioAtualizado.getNome() != null) {
usuario.setNome(usuarioAtualizado.getNome());
}
if (usuarioAtualizado.getEmail() != null) {
usuario.setEmail(usuarioAtualizado.getEmail());
}
usuario.setAtualizadoEm(LocalDateTime.now());
Usuario salvo = usuarioRepository.save(usuario);
return ResponseEntity.ok(salvo);
})
.orElse(ResponseEntity.notFound().build());
}
// DELETE - Remover usuário
@DeleteMapping("/{id}")
public ResponseEntity deletar(@PathVariable Long id) {
if (usuarioRepository.existsById(id)) {
usuarioRepository.deleteById(id);
return ResponseEntity.noContent().build();
}
return ResponseEntity.notFound().build();
}
}
Exemplos de Requisições:
// 1️⃣ GET - Listar todos os usuários
GET http://localhost:8080/api/usuarios
Accept: application/json
Resposta 200 OK:
[
{
"id": 1,
"nome": "Ana Silva",
"email": "ana@example.com",
"ativo": true,
"criadoEm": "2025-10-29T10:30:00"
},
{
"id": 2,
"nome": "Bruno Costa",
"email": "bruno@example.com",
"ativo": true,
"criadoEm": "2025-10-29T11:15:00"
}
]
---
// 2️⃣ GET - Buscar usuário específico
GET http://localhost:8080/api/usuarios/1
Accept: application/json
Resposta 200 OK:
{
"id": 1,
"nome": "Ana Silva",
"email": "ana@example.com",
"ativo": true,
"criadoEm": "2025-10-29T10:30:00"
}
---
// 3️⃣ POST - Criar novo usuário
POST http://localhost:8080/api/usuarios
Content-Type: application/json
{
"nome": "Carlos Souza",
"email": "carlos@example.com",
"senha": "senha123"
}
Resposta 201 Created:
{
"id": 3,
"nome": "Carlos Souza",
"email": "carlos@example.com",
"ativo": true,
"criadoEm": "2025-10-29T14:45:00"
}
---
// 4️⃣ PUT - Atualizar usuário completamente
PUT http://localhost:8080/api/usuarios/1
Content-Type: application/json
{
"nome": "Ana Silva Santos",
"email": "ana.silva@example.com",
"ativo": true
}
Resposta 200 OK: (usuário atualizado)
---
// 5️⃣ PATCH - Atualizar apenas o nome
PATCH http://localhost:8080/api/usuarios/1
Content-Type: application/json
{
"nome": "Ana S. Santos"
}
Resposta 200 OK: (apenas nome atualizado)
---
// 6️⃣ DELETE - Remover usuário
DELETE http://localhost:8080/api/usuarios/1
Resposta 204 No Content
7. Autenticação e Segurança
APIs precisam proteger dados sensíveis. Existem várias estratégias de autenticação:
Basic Auth:
// Envia usuário e senha em cada requisição (Base64)
GET /api/usuarios HTTP/1.1
Authorization: Basic dXN1YXJpbzpzZW5oYQ==
// dXN1YXJpbzpzZW5oYQ== é base64 de "usuario:senha"
// ✓ Simples
// ✗ Inseguro sem HTTPS
// ✗ Credenciais em toda requisição
Bearer Token:
// Cliente obtém token após autenticação
// Envia token em cada requisição
POST /api/auth/login
Content-Type: application/json
{
"email": "usuario@example.com",
"senha": "senha123"
}
Resposta 200 OK:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"tipo": "Bearer",
"expiraEm": "2025-10-30T14:30:00"
}
---
// Usar token em requisições subsequentes
GET /api/usuarios
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
JWT (JSON Web Token):
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.util.Date;
public class JwtUtil {
private static final String SECRET_KEY = "sua_chave_super_secreta_aqui_com_minimo_32_caracteres";
private static final long EXPIRATION_TIME = 86400000; // 24 horas
// Gerar token
public static String gerarToken(String email, Long usuarioId) {
return Jwts.builder()
.setSubject(email)
.claim("usuarioId", usuarioId)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(
Keys.hmacShaKeyFor(SECRET_KEY.getBytes()),
SignatureAlgorithm.HS256
)
.compact();
}
// Validar e extrair email do token
public static String extrairEmail(String token) {
return Jwts.parserBuilder()
.setSigningKey(Keys.hmacShaKeyFor(SECRET_KEY.getBytes()))
.build()
.parseClaimsJws(token)
.getBody()
.getSubject();
}
// Validar se token é válido
public static boolean validarToken(String token) {
try {
Jwts.parserBuilder()
.setSigningKey(Keys.hmacShaKeyFor(SECRET_KEY.getBytes()))
.build()
.parseClaimsJws(token);
return true;
} catch (Exception e) {
return false;
}
}
}
8. Boas Práticas para APIs
✓ Versionamento de API
- Use versões na URL: /api/v1/usuarios
- Permite evoluir sem quebrar clientes antigos
- Facilita migração gradual
✓ Nomes Descritivos e Consistentes
- Use substantivos para endpoints: /usuarios, /produtos
- Evite verbos: /obterUsuarios ❌ → /usuarios ✓
- Use plural: /produtos não /produto
✓ Tratamento de Erros
- Retorne mensagens claras e úteis
- Use status codes apropriados
- Padronize o formato de erro em JSON
✓ Documentação
- Use Swagger/OpenAPI para gerar documentação automática
- Documente todos os endpoints
- Inclua exemplos de requisição e resposta
9. Exercícios Práticos
Exercício 1: API de Tarefas
Crie uma REST API com CRUD completo (Create, Read, Update, Delete) para gerenciar tarefas. Use Spring Boot, JPA e MySQL.
Exercício 2: Integração com API Externa
Use RestTemplate ou WebClient para integrar sua aplicação com uma API pública (ex: ViaCEP para endereços). Trate erros corretamente.
Exercício 3: Autenticação com JWT
Implemente autenticação JWT em uma API existente. Crie endpoints de login e proteja outros endpoints verificando o token.
Exercício 4: Documentação com Swagger
Configure Swagger/SpringFox em um projeto Spring Boot. Documente todos os endpoints com descrições, parâmetros e exemplos.
Exercício 5: Tratamento Centralizado de Erros
Crie um @ControllerAdvice que padroniza respostas de erro em JSON com mensagens claras e status codes apropriados.
Conclusão
APIs são a espinha dorsal da web moderna e comunicação entre sistemas. Entender seus conceitos é essencial para qualquer desenvolvedor.
Pontos-chave para lembrar:
- REST é o padrão mais popular para APIs web
- HTTP métodos definem as operações (GET, POST, PUT, DELETE, PATCH)
- Status codes comunicam o resultado da operação
- Autenticação é essencial para proteger dados
- Documentação e boas práticas tornam a API usável e mantível
Pratique criando suas próprias APIs e integrando-se com APIs de terceiros. Isso é um dos conhecimentos mais valiosos no desenvolvimento moderno! 🚀