🔀 CAPÍTULO 14: DIAGRAMA DE SEQUÊNCIA E APIS REST


🎯 1. Objetivos de Aprendizagem & Competências

Estimativa de Dedicação: 2 horas de estudo autoguiado.
Ao final deste capítulo, você será capaz de:

  • 🔹 Compreender a representação temporal de troca de mensagens entre objetos no Diagrama de Sequência da UML 2.5.
  • 🔹 Dominar a sintaxe visual de Linhas de Vida (Lifelines), Barras de Ativação (Execution Occurrences), Mensagens Síncronas (->>), Assíncronas (-)) e Retornos (-->>).
  • 🔹 Modelar fluxos completos de requisições HTTP REST (Request-Response Cycle) conectando Cliente, Gateway, Serviços e Banco de Dados.
  • 🔹 Implementar rotas Flask integradas com serviços de domínio espelhando rigorosamente a ordem do diagrama de sequência.

🏢 2. Cenário Corporativo & Estudo de Caso (TecProExpress)

Na TecProExpress, a equipe de engenharia identificou uma latência excessiva durante o processo de Checkout e Emissão de Etiqueta. O time de frontend culpava o banco de dados, o DBA culpava a rede e a equipe backend culpava a API externa de CEP.

O Desafio: Como Arquiteto de Software, você deve desenhar o Diagrama de Sequência da UML para rastrear a linha do tempo exata das chamadas de rede e processamento síncrono/assíncrono, identificando gargalos e estabelecendo contratos REST claros e determinísticos em Flask.


🧠 3. Fundamentação Teórica & Modelos Visuais

3.1. Anatomia do Diagrama de Sequência da UML

O tempo flui verticalmente de cima para baixo. Cada participante possui uma linha de vida vertical com barras que indicam períodos em que o objeto está executando operações ativas:

sequenceDiagram
    autonumber
    actor C as 📱 App do Motorista
    participant API as 🌐 Flask (Gateway)
    participant SVC as 🧠 FreteService
    participant DB as 🛢️ PostgreSQL
    
    C->>+API: POST /api/fretes/calcular (distancia_km, peso_kg, expresso)
    API->>+SVC: processar_calculo(distancia, peso, expresso)
    SVC->>+DB: SELECT taxa_km FROM tabelas_frete...
    DB-->>-SVC: taxa_km = 2.50
    SVC-->>-API: { valor_total: 316.25, prazo_horas: 24 }
    API-->>-C: 200 OK { valor_total: 316.25, prazo_horas: 24 }

3.2. Notação de Mensagens na UML 2.5

Notação MermaidTipo de Mensagem UMLSignificado de Engenharia
->> (Seta sólida preenchida)Mensagem SíncronaO chamador bloqueia a execução aguardando o retorno da resposta.
-) (Seta fina aberta)Mensagem AssíncronaO chamador envia o evento e prossegue sem esperar (ex: disparo de fila RabbitMQ/Kafka).
-->> (Seta pontilhada)Mensagem de RetornoRetorno de dados ou confirmação de conclusão da operação.
par / and / endFragmento ParaleloExecução concorrente de múltiplos fluxos simultâneos.
alt / else / endFragmento CondicionalEstrutura de desvio if / else na sequência.

💻 4. Aplicação Prática & Código Executável (Python 3.11+)

📋 Pré-requisitos e Instalação

Instale o micro-framework Flask no seu ambiente virtual:

pip install flask

💻 Código Completo e Autocontido (sequence_api_frete.py)

Implementação do fluxo síncrono de cálculo de frete com Flask 3.x, refletindo a interação modelada no Diagrama de Sequência:

"""
Módulo: sequence_api_frete.py
Domínio: Endpoint REST Flask refletindo a sequência síncrona de cálculo de frete.
"""
from decimal import Decimal
import sys
from flask import Flask, request, jsonify

app = Flask(__name__)

# 1. Camada de Serviço (Service Layer)
class FreteService:
    @staticmethod
    def processar_calculo(distancia_km: Decimal, peso_kg: Decimal, expresso: bool = False) -> dict:
        taxa_base_km = Decimal("2.50")
        valor = (distancia_km * taxa_base_km) + (peso_kg * Decimal("3.00"))
        prazo = 24
        
        if expresso:
            valor *= Decimal("1.25")
            prazo = 8
            
        return {
            "valor_total": float(valor.quantize(Decimal("0.01"))),
            "prazo_horas": prazo,
            "status": "CALCULADO_COM_SUCESSO"
        }

# 2. Rota REST (Controller / Gateway)
@app.post("/api/fretes/calcular")
def endpoint_calcular_frete():
    """Reflete o Passo 1 do Diagrama de Sequência: POST /api/fretes/calcular."""
    dados = request.get_json()
    if not dados:
        return jsonify({"erro": "Payload JSON ausente ou inválido"}), 400

    try:
        distancia = Decimal(str(dados.get("distancia_km", 0)))
        peso = Decimal(str(dados.get("peso_kg", 0)))
        expresso = bool(dados.get("expresso", False))

        if distancia <= Decimal("0.00") or peso <= Decimal("0.00"):
            return jsonify({"erro": "distancia_km e peso_kg devem ser maiores que zero"}), 400

        resultado = FreteService.processar_calculo(distancia, peso, expresso)
        return jsonify(resultado), 200

    except Exception as ex:
        return jsonify({"erro": f"Falha no processamento: {str(ex)}"}), 400

if __name__ == "__main__":
    if "--server" in sys.argv:
        print("🚀 Iniciando servidor Flask em http://127.0.0.1:5000...")
        app.run(port=5000, debug=True)
    else:
        print("--- Simulação de Requisições HTTP com Flask test_client() ---")
        with app.test_client() as client:
            # Cenário 1: Frete Padrão (120.5 km, 5 kg) -> (120.5*2.50) + (5*3.00) = 301.25 + 15 = 316.25
            res1 = client.post("/api/fretes/calcular", json={
                "distancia_km": 120.5,
                "peso_kg": 5.0,
                "expresso": False
            })
            print(f"Cenário 1 (Frete Padrão) [Status {res1.status_code}]: {res1.get_json()}")

            # Cenário 2: Frete Expresso (120.5 km, 5 kg, expresso) -> 316.25 * 1.25 = 395.31
            res2 = client.post("/api/fretes/calcular", json={
                "distancia_km": 120.5,
                "peso_kg": 5.0,
                "expresso": True
            })
            print(f"Cenário 2 (Frete Expresso) [Status {res2.status_code}]: {res2.get_json()}")

            # Cenário 3: Validação de Payload com Erro
            res3 = client.post("/api/fretes/calcular", json={
                "distancia_km": -10.0,
                "peso_kg": 5.0
            })
            print(f"Cenário 3 (Validação Defensiva) [Status {res3.status_code}]: {res3.get_json()}")

🚀 Como Executar

Execute o script de teste automatizado diretamente no terminal:

python sequence_api_frete.py

Para iniciar o servidor HTTP e testar com ferramentas como Postman, cURL ou VS Code REST Client:

python sequence_api_frete.py --server

🖥️ Saída Esperada no Terminal

--- Simulação de Requisições HTTP com Flask test_client() ---
Cenário 1 (Frete Padrão) [Status 200]: {'prazo_horas': 24, 'status': 'CALCULADO_COM_SUCESSO', 'valor_total': 316.25}
Cenário 2 (Frete Expresso) [Status 200]: {'prazo_horas': 8, 'status': 'CALCULADO_COM_SUCESSO', 'valor_total': 395.31}
Cenário 3 (Validação Defensiva) [Status 400]: {'erro': 'distancia_km e peso_kg devem ser maiores que zero'}

💡 5. Checkpoint de Engenharia & Boas Práticas

Boas Práticas & Anti-Patterns

  • Contratos REST Claros e Validados: Toda API REST deve validar rigorosamente os payloads de entrada e retornar códigos HTTP semânticos (200 para sucesso, 400 para erro de validação do cliente, 500 para falha interna), com payloads JSON estruturados e previsíveis.
  • Anti-Pattern Excesso de Chamadas Síncronas (Chatty API): Evite criar sequências onde a API faz múltiplas consultas síncronas sequenciais desnecessárias. Agrupe chamadas ou adote processamento assíncrono para operações de longa duração.

🔗 6. Conexão com os Projetos Integradores

Projeto IntegradorComo o conceito deste capítulo é aplicado no PI
PI-05: ParkFlowDiagrama de Sequência do checkout do estacionamento (leitura de ticket ➔ tarifação ➔ baixa).
PI-10: ImobiFlowSequência de geração de fatura de aluguel e cálculo do repasse financeiro líquido ao proprietário.

🧪 7. Quiz de Fixação e Autoavaliação (Formative Assessment)

🧪 Quiz de Autoavaliação — Capítulo 14

1. No Diagrama de Sequência da UML, o que representa a 'Linha de Vida' (Lifeline) de um objeto?

  • A) O número de bytes que o objeto ocupa na memória RAM.
  • B) Uma linha vertical pontilhada que representa a existência e a passagem do tempo daquele participante durante a interação.
  • C) O cabo de rede que conecta os servidores.
  • D) A chave estrangeira que conecta duas tabelas no banco de dados.
💡 Ver Resposta e Justificativa

Resposta Correta: B
Justificativa: A linha de vida estende-se verticalmente para baixo a partir do retângulo do participante, representando a passagem cronológica do tempo na interação.


2. Qual é a diferença fundamental entre uma 'Mensagem Síncrona' e uma 'Mensagem Assíncrona' no diagrama de sequência?

  • A) A síncrona usa JavaScript e a assíncrona usa Python.
  • B) Na síncrona, o remetente pausa e aguarda a conclusão da resposta antes de continuar; na assíncrona, o remetente envia a mensagem e continua seu processamento imediatamente sem bloquear.
  • C) A mensagem assíncrona não pode conter parâmetros.
  • D) Não há diferença; a UML 2.5 unificou as duas mensagens.
💡 Ver Resposta e Justificativa

Resposta Correta: B
Justificativa: Mensagens síncronas bloqueiam o fluxo do chamador até a resposta (ex: chamada de função comum), enquanto mensagens assíncronas disparam eventos em segundo plano (ex: postagem em fila).


3. O que define o fragmento de interação combinado 'alt' (Alternative) no diagrama de sequência?

  • A) Um loop que repete a operação infinitamente.
  • B) Uma bifurcação condicional com guardas booleanas (equivalente a uma estrutura if / else).
  • C) Uma falha irrecuperável do sistema operacional.
  • D) A exclusão física de um registro no banco de dados.
💡 Ver Resposta e Justificativa

Resposta Correta: B
Justificativa: O operador 'alt' modela caminhos mutuamente exclusivos baseados em condições de guarda (ex: [Saldo Suficiente] vs [Saldo Insuficiente]).


🛠️ 8. Ponte para a Ação: Laboratório Prático

🎯 Próximo Passo Prático

Coloque esta teoria em prática executando o roteiro de laboratório autoguiado:
👉 ATIVIDADE 08: DIAGRAMA DE SEQUÊNCIA (UML)


📌 9. Resumo Executivo & Key Takeaways

  • Visão Temporal: O Diagrama de Sequência é o modelo comportamental mais utilizado para mapear a ordem cronológica de APIs REST e microsserviços.
  • Linhas de Vida & Barras de Ativação: Indicam os participantes e os momentos exatos de processamento ativo.
  • Mensagens Síncronas vs Assíncronas: Diferenciam chamadas diretas de eventos desacoplados em filas e mensageria.
  • Endpoints em Flask: Implementam de forma limpa e síncrona as transições modeladas no diagrama de sequência, facilitando testes com test_client().