Conectando Sistemas com APIs REST e Webhooks: Guia Prático

Conectando Sistemas com APIs REST e Webhooks: Guia Prático
Introdução
Em um cenário onde aplicações precisam trocar dados de forma rápida, segura e escalável, APIs e webhooks tornaram‑se os pilares das integrações modernas. Enquanto as APIs REST permitem que um cliente solicite recursos sob demanda, os webhooks entregam eventos de forma assíncrona, reduzindo a necessidade de polling constante.
Este artigo apresenta, de forma prática, como planejar, implementar e manter integrações entre sistemas usando:
APIs REST (HTTP/JSON); Webhooks para eventos em tempo real; Estratégias de autenticação e controle de tráfego; Documentação automática com OpenAPI/Swagger.
Ao final, você terá código funcional em Python (Flask) e Node.js (Express) que pode ser copiado e adaptado ao seu projeto.
1. Conceitos Fundamentais de APIs e Webhooks
| Característica | API REST | Webhook |
|---|---|---|
| Iniciação | Cliente solicita (pull) | Servidor envia (push) |
| Formato | HTTP + JSON (ou XML) | HTTP POST com payload JSON |
| Uso típico | CRUD de recursos, consultas | Notificações de eventos (ex.: pagamento concluído) |
| Escalabilidade | Depende de taxa de requisições | Depende de volume de eventos gerados |
| Segurança | Autenticação por token, OAuth2, API keys | Validação de assinatura, secret token |
1.1 Quando usar cada abordagem?
1.2 Principais padrões de comunicação
JSON – Formato de dados leve e amplamente suportado. HTTPS – Obrigatório para proteger a confidencialidade e integridade dos dados. Status codes – Use códigos HTTP corretos (200, 201, 400, 401, 429, 500) para facilitar o tratamento de erros.
2. Estratégias de Autenticação e Controle de Tráfego
2.1 OAuth2 – O padrão de fato
OAuth2 permite que um cliente obtenha um access token que será enviado em cada requisição via cabeçalho Authorization: Bearer . O fluxo Client Credentials é o mais simples para integrações máquina‑a‑máquina.
Exemplo de request de token (cURL)
curl -X POST https://auth.example.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=MY_CLIENT_ID&client_secret=MY_CLIENT_SECRET"
Resposta:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6...",
"token_type": "Bearer",
"expires_in": 3600
}
2.2 API Keys e HMAC
Para webhooks, a prática mais comum é enviar um secret compartilhado que o receptor usa para gerar um HMAC SHA‑256 da carga e comparar com o cabeçalho X-Signature. Isso garante que a chamada realmente veio da origem esperada.
Exemplo de validação em Node.js (Express)
const crypto = require('crypto');
function verifySignature(req, res, next) {
const signature = req.headers['x-signature'];
const payload = JSON.stringify(req.body);
const secret = process.env.WEBHOOK_SECRET;
const hash = crypto.createHmac('sha256', secret).update(payload).digest('hex');
if (hash !== signature) {
return res.status(401).send('Invalid signature');
}
next();
}
2.3 Rate Limiting
Para evitar sobrecarga, implemente rate limiting por IP ou por token. Bibliotecas como express-rate-limit (Node.js) ou Flask-Limiter (Python) facilitam a configuração.
Exemplo rápido em Flask
from flask import Flask, request, jsonify
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
app = Flask(__name__)
limiter = Limiter(app, key_func=get_remote_address)
@app.route('/clientes', methods=['GET'])
@limiter.limit("100 per minute")
def listar_clientes():
# lógica de listagem
return jsonify([...])
3. Padronização e Documentação com OpenAPI
A OpenAPI Specification (OAS) permite descrever toda a API em um único documento YAML/JSON. Ferramentas como Swagger UI ou Redoc geram documentação interativa automaticamente.
3.1 Estrutura mínima de um spec
openapi: 3.0.3
info:
title: API de Pedidos
version: 1.0.0
servers:
- url: https://api.example.com/v1
paths:
/pedidos:
get:
summary: Lista todos os pedidos
security:
- bearerAuth: []
responses:
'200':
description: Lista de pedidos
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Pedido'
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
Pedido:
type: object
properties:
id:
type: integer
status:
type: string
total:
type: number
format: float
3.2 Gerando código a partir do spec
Ferramentas como openapi-generator criam stubs em diversas linguagens. Por exemplo:
openapi-generator-cli generate -i api.yaml -g python-flask -o ./generated-flask
Isso gera um esqueleto de API Flask já com rotas, validação de entrada e documentação Swagger integrada.
Exemplos Práticos
3.1 API REST em Python (Flask)
# app.py
from flask import Flask, request, jsonify, abort
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
import requests
import os
app = Flask(__name__)
limiter = Limiter(app, key_func=get_remote_address)
API_KEY = os.getenv('API_KEY')
WEBHOOK_URL = os.getenv('WEBHOOK_URL')
def authorize():
token = request.headers.get('Authorization')
if not token or token != f'Bearer {API_KEY}':
abort(401, description='Invalid token')
@app.route('/clientes', methods=['GET'])
@limiter.limit('60/minute')
def listar_clientes():
authorize()
# Simulação de dados
clientes = [
{"id": 1, "nome": "Ana", "email": "ana@example.com"},
{"id": 2, "nome": "Bruno", "email": "bruno@example.com"},
]
return jsonify(clientes)
@app.route('/clientes', methods=['POST'])
@limiter.limit('30/minute')
def criar_cliente():
authorize()
data = request.get_json()
if not data.get('nome') or not data.get('email'):
abort(400, description='Nome e e‑mail são obrigatórios')
# Persistir no banco (omisso)
novo = {"id": 3, data}
# Dispara webhook de criação
payload = {"event": "cliente.criado", "data": novo}
headers = {
"Content-Type": "application/json",
"X-Signature": generate_hmac(payload)
}
requests.post(WEBHOOK_URL, json=payload, headers=headers)
return jsonify(novo), 201
def generate_hmac(payload):
import hmac, hashlib, json
secret = os.getenv('WEBHOOK_SECRET').encode()
message = json.dumps(payload).encode()
return hmac.new(secret, message, hashlib.sha256).hexdigest()
if __name__ == '__main__':
app.run(debug=True)
Pontos chave do exemplo
Rate limiting com flask_limiter.
Autenticação simples via token no cabeçalho.
Webhook disparado após criação de cliente, usando HMAC para assinatura.
3.2 API REST em Node.js (Express)
``js
// server.js
require('dotenv').config();
const express = require('express');
const rateLimit = require('express-rate-limit');
const axios = require('axios');
const crypto = require('crypto');
const app = express(); app.use(express.json());
const limiter = rateLimit({ windowMs: 60 * 1000, max: 80, // 80 req/min por IP }); app.use(limiter);
const API_KEY = process.env.API_KEY; const WEBHOOK_URL = process.env.WEBHOOK_URL; const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
function verifyAuth(req, res, next) { const auth = req.headers.authorization; if (!auth || auth !== Bearer ${API_KEY}`) { return res.status(401).json({ error: 'Invalid token' }); } next(); }
app.get('/produtos', verifyAuth, (req, res) => { const produtos = [ { id: 10, nome: 'Camiseta', preco: 49.9 }, { id: 11, nome: 'Caneca', preco: 29.9 }, ]; res.json(produtos); });
app.post('/pedidos', verifyAuth, async (req, res) => { const { clienteId, itens } = req.body; if (!clienteId || !Array.isArray(itens) || itens.length === 0) { return res.status(400).json({ error: 'Payload inválido' }); }
const pedido = { id: 1001, clienteId, itens, status: 'criado' };
// Envia webhook de novo pedido const payload = { event: 'pedido.criado', data: pedido }; const signature = crypto .createHmac('sha256', WEBHOOK_SECRET) .update(JSON.stringify(payload)) .digest('hex');
try { await axios.post(WEBHOOK_URL, payload, { headers: { 'X-Signature': signature, 'Content-Type': 'application/json' }, }); } catch (


