APIs REST e Bounded Contexts

Implementando Payment, Notification e Analytics

Você implementa APIs iniciais em Go, Ruby e Node para completar o ecossistema de cinco serviços.

Avançado 55 min 35 pontos Leitura 0%

Nesta aula você vai

  • Criar endpoints reais para Payment, Notification e Analytics
  • Padronizar payload e respostas entre stacks diferentes
  • Deixar os serviços prontos para integração por eventos

Implementando Payment, Notification e Analytics

Objetivos

  • Criar endpoints reais para Payment, Notification e Analytics
  • Padronizar payload e respostas entre stacks diferentes
  • Deixar os serviços prontos para integração por eventos

Pré-requisitos

  • customer-service e order-service já implementados
  • Docker Compose operacional
  • Familiaridade com APIs REST

Conceito

Microsserviço "vazio" é dívida técnica disfarçada. Mesmo uma API simples precisa nascer com contrato claro, validação mínima e logs consistentes. Se payment, notification e analytics começarem sem padrão, o fluxo distribuído quebra quando os eventos chegarem.

Ao implementar os três serviços agora, você fecha o ecossistema base do e-commerce. Isso permite testar fluxos reais fim a fim e evita desenvolver integração assíncrona em cima de stubs frágeis.

Nesta aula, cada stack recebe código funcional de produção didática: Go Gin no pagamento, Ruby Sinatra para notificação e Node Express para analytics.

Estrutura de arquivos

services/
  payment-service/
    cmd/api/main.go
  notification-service/
    app.rb
  analytics-service/
    src/server.js

Passo a passo

  1. Implementar API de pagamento em Go (payment-service/cmd/api/main.go)
package main

import (
  "net/http"
  "github.com/gin-gonic/gin"
)

type CreatePaymentRequest struct {
  OrderID string  `json:"orderId" binding:"required"`
  Amount  float64 `json:"amount" binding:"required,gt=0"`
}

func main() {
  router := gin.Default()

  router.GET("/health", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"status": "ok", "service": "payment-service"})
  })

  router.POST("/payments", func(c *gin.Context) {
    var req CreatePaymentRequest
    if err := c.ShouldBindJSON(&req); err != nil {
      c.JSON(http.StatusBadRequest, gin.H{"error": "payload inválido"})
      return
    }
    c.JSON(http.StatusCreated, gin.H{
      "paymentId": "pay-" + req.OrderID,
      "orderId": req.OrderID,
      "status": "PROCESSING",
    })
  })

  router.Run(":8080")
}
  1. Implementar API de notificação em Ruby (notification-service/app.rb)
require "sinatra"
require "json"

set :port, 4567
set :bind, "0.0.0.0"

NOTIFICATIONS = []

get "/health" do
  content_type :json
  { status: "ok", service: "notification-service" }.to_json
end

post "/notifications" do
  payload = JSON.parse(request.body.read)
  halt 400, { error: "customerId obrigatório" }.to_json unless payload["customerId"]
  halt 400, { error: "message obrigatório" }.to_json unless payload["message"]

  item = { id: "not-#{NOTIFICATIONS.length + 1}", customerId: payload["customerId"], message: payload["message"] }
  NOTIFICATIONS << item
  status 201
  item.to_json
end
  1. Implementar API de analytics em Node (analytics-service/src/server.js)
const express = require("express");
const app = express();
app.use(express.json());

const counters = {};

app.get("/health", (_req, res) => {
  res.json({ status: "ok", service: "analytics-service" });
});

app.post("/analytics/events", (req, res) => {
  const { type } = req.body;
  if (!type) return res.status(400).json({ error: "type é obrigatório" });
  counters[type] = (counters[type] || 0) + 1;
  return res.status(202).json({ received: true, type, total: counters[type] });
});

app.get("/analytics/events/:type", (req, res) => {
  const total = counters[req.params.type] || 0;
  res.json({ type: req.params.type, total });
});

app.listen(3000, "0.0.0.0");
  1. Ajustar docker-compose.yml com portas desses serviços
payment-service:
  build: ../services/payment-service
  ports: ["8080:8080"]

notification-service:
  build: ../services/notification-service
  ports: ["4567:4567"]

analytics-service:
  build: ../services/analytics-service
  ports: ["3000:3000"]

Como testar

  1. Subir serviços:
docker compose -f infra/docker-compose.yml up --build -d payment-service notification-service analytics-service
  1. Testar pagamento:
curl -s -X POST http://localhost:8080/payments \
  -H "Content-Type: application/json" \
  -d '{"orderId":"ord-100","amount":89.9}'

Esperado: status: "PROCESSING".

  1. Testar notificação:
curl -s -X POST http://localhost:4567/notifications \
  -H "Content-Type: application/json" \
  -d '{"customerId":"cli-10","message":"Pagamento recebido"}'
  1. Testar analytics:
curl -s -X POST http://localhost:3000/analytics/events \
  -H "Content-Type: application/json" \
  -d '{"type":"payment.approved"}'
curl -s http://localhost:3000/analytics/events/payment.approved

Esperado: total maior que zero.

Dicas de projeto

  • Padronize service e status nos endpoints de saúde.
  • Use JSON em todas as respostas para consistência operacional.
  • Mantenha validação mínima de payload desde o início.
  • Inclua exemplos de curl no README de cada serviço.

Erros comuns

  • Misturar regra de notificação dentro do serviço de pagamento.
  • Retornar status HTTP incorreto em erro de validação.
  • Criar API de analytics sem idempotência mínima.
  • Ignorar logs de entrada/saída em serviços críticos.

Resumo

Os três serviços complementares agora têm APIs funcionais e testáveis, com padrões consistentes de entrada e saída. A arquitetura está pronta para entrar no módulo de Kafka e fluxos orientados a eventos.