🔌 ATIVIDADE 14: DESIGN DE APIS REST E SWAGGER
Para realizar este laboratório com sucesso, certifique-se de ter compreendido os conceitos apresentados no:
👉 CAPÍTULO 14: DIAGRAMA DE SEQUÊNCIA
Bem-vindo a mais uma etapa prática de Engenharia de Software! Agora que você conhece as camadas internas do software, aprenderá como expor e conectar o seu sistema ao mundo externo. Hoje, vamos nos tornar arquitetos de comunicação móvel e web, projetando contratos de integração baseados em APIs RESTful, payloads de dados JSON e documentando tudo com o padrão profissional global Swagger (OpenAPI). 🛡️🧩
🎯 Objetivos de Aprendizagem do Laboratório
Ao final deste laboratório prático (estimativa: 4 horas presenciais / autoguiadas), você será capaz de:
- Mapear recursos de sistemas no formato e boas práticas de APIs REST.
- Utilizar os Verbos HTTP (GET, POST, PUT, DELETE) e os Códigos de Retorno (Status Codes) corretos.
- Escrever payloads estruturados em formato JSON (JavaScript Object Notation).
- Interpretar e projetar documentações no padrão Swagger/OpenAPI.
🏢 O Cenário Prático (Seu Desafio)
Na TecProExpress, os motoristas que usam o aplicativo Android precisam enviar em tempo real a geolocalização do caminhão para o painel de controle do SAC. Além disso, o app precisa buscar a lista de entregas pendentes direto do servidor central. No entanto, os desenvolvedores Mobile e os programadores de Backend não combinaram o "formato de dados" e a comunicação travou!
O app móvel mandava POST /api/enviar_localizacao e o servidor dava erro de conexão porque esperava receber um formato diferente do JSON enviado pelo celular!
"Seu desafio como Designer de APIs é desenhar o contrato profissional de endpoints para a TecProExpress. Você criará a modelagem de recursos RESTful para
/api/entregase/api/motoristas/localizacao, definindo os verbos corretos, os dados em formato JSON e gerando a especificação profissional baseada em Swagger/OpenAPI."
🧠 Fundamentos: A Teoria Traduzida
Uma API (Application Programming Interface) é uma porta que permite que sistemas diferentes conversem de forma organizada. REST é o estilo arquitetural padrão da web.
Regras de Ouro do Design REST:
- Recursos são Substantivos no Plural: Evite verbos no endereço!
- Errado:
POST /api/salvarMotorista - Certo:
POST /api/motoristas
- Errado:
- Use os Verbos HTTP Adequados:
GET: Busca um ou vários registros (Ex:GET /api/entregas).POST: Cria um novo registro (Ex:POST /api/entregas).PUT: Atualiza o registro inteiro por completo.DELETE: Exclui um registro da base de dados.
- Comunique-se por Status Codes:
200 OK: Requisição de consulta ou alteração com sucesso.201 Created: Novo registro criado com sucesso (retorno típico de POST).400 Bad Request: Envio de dados incorretos ou campos faltantes.404 Not Found: O registro ou endpoint consultado não existe.500 Internal Server Error: Falha técnica no servidor (bug).
📊 Visualizando a Comunicação HTTP e Swagger
sequenceDiagram
autonumber
actor Cliente as 📱 App Mobile / Frontend
participant API as 🌐 Flask Router
participant Schema as 🛡️ Validação de Payload
participant DB as 🗄️ PostgreSQL
Cliente->>API: POST /api/entregas (JSON Payload)
API->>Schema: Valida Tipos e Constraints
alt Dados Válidos
Schema-->>API: Dados Aprovados
API->>DB: INSERT INTO entregas (...)
DB-->>API: Confirmação de Persistência
API-->>Cliente: 201 Created { "id": 125, "status": "PENDENTE" }
else Dados Inválidos
Schema-->>API: Erro de Validação (ex: peso <= 0)
API-->>Cliente: 400 Bad Request (JSON com detalhes do erro)
end
📖 Exemplo Guiado: Especificação OpenAPI / Swagger e API em Flask
No Flask, implementamos a lógica de rota e validação em Python, e documentamos o contrato correspondente no padrão OpenAPI 3.0 (Swagger):
🛠️ Código Python 3.11 no Flask (app_entregas.py):
import sys
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.post("/api/entregas")
def criar_entrega():
"""Cria uma nova entrega e retorna o objeto persistido."""
dados = request.get_json()
if not dados:
return jsonify({"erro": "Payload JSON ausente"}), 400
cliente_id = dados.get("cliente_id")
endereco_destino = dados.get("endereco_destino")
peso_carga_kg = dados.get("peso_carga_kg", 0.0)
tipo_notificacao = dados.get("tipo_notificacao", "SMS")
if not cliente_id or not endereco_destino:
return jsonify({"erro": "cliente_id e endereco_destino são obrigatórios"}), 400
if peso_carga_kg <= 0:
return jsonify({"erro": "peso_carga_kg deve ser maior que zero"}), 400
resposta = {
"id": 125,
"cliente_id": cliente_id,
"endereco_destino": endereco_destino,
"peso_carga_kg": peso_carga_kg,
"tipo_notificacao": tipo_notificacao,
"status": "PENDENTE"
}
return jsonify(resposta), 201
if __name__ == "__main__":
if "--server" in sys.argv:
print("🚀 Servidor de Entregas Flask rodando em http://127.0.0.1:5000")
app.run(port=5000, debug=True)
else:
print("--- Teste Automatizado com Flask test_client() ---")
with app.test_client() as client:
res = client.post("/api/entregas", json={
"cliente_id": 45,
"endereco_destino": "Av. Paulista, 1000 - São Paulo, SP",
"peso_carga_kg": 12.5,
"tipo_notificacao": "SMS"
})
print(f"Status HTTP: {res.status_code}")
print(f"Resposta JSON: {res.get_json()}")
📄 O Contrato JSON enviado pelo App Mobile (Payload):
{
"cliente_id": 45,
"endereco_destino": "Av. Paulista, 1000 - São Paulo, SP",
"peso_carga_kg": 12.5,
"tipo_notificacao": "SMS"
}
📄 Documentação Swagger (OpenAPI 3.0 YAML) correspondente:
openapi: 3.0.3
info:
title: API TecProExpress
version: 1.0.0
paths:
/api/entregas:
post:
summary: Criar nova entrega
tags:
- Entregas
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- cliente_id
- endereco_destino
properties:
cliente_id:
type: integer
endereco_destino:
type: string
peso_carga_kg:
type: number
tipo_notificacao:
type: string
responses:
'201':
description: Criado com sucesso
'400':
description: Dados inválidos
💻 Execução do Servidor Flask & Teste cURL no Terminal
Para iniciar o servidor e executar requisições reais contra a API:
🔹 1. Iniciar Servidor:
python app_entregas.py --server
🔹 2. Requisição cURL enviando o Payload JSON:
curl -X POST "http://127.0.0.1:5000/api/entregas" \
-H "Content-Type: application/json" \
-d '{
"cliente_id": 45,
"endereco_destino": "Av. Paulista, 1000 - São Paulo, SP",
"peso_carga_kg": 12.5,
"tipo_notificacao": "SMS"
}'
🖥️ Saída Esperada no Terminal:
HTTP/1.1 201 Created
content-type: application/json
{
"cliente_id": 45,
"endereco_destino": "Av. Paulista, 1000 - São Paulo, SP",
"peso_carga_kg": 12.5,
"tipo_notificacao": "SMS",
"id": 125,
"status": "PENDENTE"
}
🛠️ Prática Obrigatória 1: Tabela de Endpoints da API
Cenário: O projeto semestral da sua equipe.
- Mapeie 3 endpoints críticos que o seu sistema precisará expor para um aplicativo celular ou sistema parceiro.
- Organize-os em uma tabela contendo: Verbo HTTP, Caminho (URL), O que faz (Descrição) e Status Code de Sucesso (ex: 200, 201).
🏁 Resultado Esperado (Para sua Referência)
Uma tabela com o roteiro de comunicação REST detalhando as requisições principais de forma limpa e seguindo as boas práticas.
🛠️ Prática Obrigatória 2: O Payload JSON e Contrato Swagger
Cenário: Detalhando os dados de tráfego.
- Para o endpoint principal de inserção de dados da Prática 1 (Ex: criar agendamento, realizar venda), escreva o payload em formato JSON real que o cliente enviará.
- Escreva a especificação profissional simplificada no padrão Swagger/OpenAPI (formato YAML) que descreve esse endpoint e o corpo da requisição de forma estruturada.
📤 Instruções de Entrega (Microsoft Teams)
Após validar o seu design de API:
- Salve o arquivo contendo a tabela de endpoints, o JSON e a especificação Swagger YAML com o nome
Atividade_14.mdna pastaes-atv-14-apis-swagger/do seu repositório GitHub. - Certifique-se de fazer o commit e push para o repositório público.
- Submeta o link do seu repositório no Microsoft Teams para avaliação do professor.
💡 Checkpoint de Lógica
Reflexão Profissional:
Por que no design REST profissional, nunca usamos o verbo GET para realizar a deleção de um dado (ex: GET /api/entregas/excluir?id=5) em vez do correto DELETE (ex: DELETE /api/entregas/5)? (Resposta: Pela natureza idempotente e segura dos verbos HTTP. Navegadores e proxies de cache assumem que requisições GET são seguras e não causam efeitos colaterais. Se você usar GET para excluir, um robô de busca de indexação automática da internet ao varrer os links do seu sistema poderia, acidentalmente, apagar o banco de dados inteiro da empresa!). 🧠🛡️
📊 Rubrica Formativa de Avaliação
| Critério de Avaliação | Insuficiente (0% - 40%) | Regular (41% - 70%) | Excelente (71% - 100%) |
|---|---|---|---|
| Design de Endpoints REST & Verbos HTTP | Usa verbos incorretos (ex: GET para exclusão) ou URLs fora do padrão RESTful. | Mapeia os 3 endpoints mas omite códigos de status de resposta (Status Codes). | Tabela de endpoints impecável com verbos HTTP semânticos (GET, POST, PUT, DELETE) e Status Codes corretos (200, 201, 204). |
| Payload JSON & Especificação Swagger OpenAPI YAML | Erros na sintaxe JSON ou formato YAML desalinhado. | Escreve o JSON mas omite a especificação Swagger YAML. | Payload JSON de requisição perfeito e contrato OpenAPI 3.0 YAML completamente válido. |
| Entrega no GitHub | Entrega fora da pasta `es-atv-14-apis-swagger/`. | Arquivo entregue mas com formatação YAML quebrada. | Submete `Atividade_14.md` com formatação limpa e blocos de código formatados no repositório. |