Início/Blog/APIs confiáveis
Arquitetura de APIs Resilientes

Construindo APIs confiáveis para redes de alta variância

Em rede móvel, satélite, banda larga rural, Wi-Fi lotado ou veículo em movimento, a chamada pode ter chegado ao servidor e a resposta ter se perdido. A banda muda no meio do upload e a reconexão troca de rota. O contrato da API precisa tornar essa incerteza segura.

Projete para variância, não para a média

Meça DNS, conexão, TLS, upload, processamento, first byte, download, perda, reconexões e transições de rádio. Segmente por país, operadora/ASN, rede, app, dispositivo, endpoint, payload e tentativa. p50 esconde quem cruza o timeout repetidamente.

RTT altoCada handshake e dependência sequencial custa caro. Reuse conexão, reduza chatty calls e faça batch com limite.
Perda e troca de rotaA conexão trava ou reseta e o cliente não sabe se o write foi confirmado.
Banda variávelResposta pequena funciona; mídia ou lista ilimitada falha no meio.
Disponibilidade intermitenteO app alterna entre online, captive, degradado, background e offline; a intenção sobrevive ao processo.

Dê um deadline ponta a ponta

A operação precisa de um orçamento, não de 30 segundos em cada hop. Reserve DNS/connect/TLS, primeira tentativa, retry opcional, parsing e feedback. Propague o saldo para downstream e cancele trabalho abandonado. Separe timeout de conexão de request/idle timeout.

DNS
Conectar
TLS
Try 1
Jitter
Try 2
Limite
Parse
UI

Retry depende de método, falha e orçamento

Retry GET/HEAD em falha transitória. PUT/DELETE podem ser idempotentes por contrato, mas a implementação ainda pode disparar efeitos externos. Não repita POST/PATCH automaticamente sem contrato de idempotência. Validação, autenticação, autorização, conflito e not-found permanente não são perda de pacote.

Backoff exponencial limitado com full jitter
T+0Tentativa 1Envie request ID, deadline e idempotency key quando necessária.
falha transitória → aleatório 0..base
T+Δ1Tentativa 2Reuse o ID lógico e pare se orçamento/política não permitirem.
aleatório 0..min(cap, base × 2²)
T+Δ2Tentativa finalRetorne estado recuperável, enfileire ou mostre falha. Nunca repita indefinidamente.

Coloque retry em uma camada

SDK 3x, gateway 3x e serviço 3x transformam uma ação em 27 chamadas. Escolha a camada que conhece semântica e budget. Use retry quota/token bucket, limite de tentativas/atraso, full jitter, Retry-After e desligamento em falha sustentada.

ResultadoInterpretaçãoPolíticaContrato do servidorEvitar
Conexão perdida sem respostaOutcome do write desconhecido.Retry só se seguro/idempotente ou keyed.Status consultável pela key/ID.Criar compra duas vezes.
408 / timeoutNão concluiu no contexto.Retry limitado se houver budget.Parar trabalho abandonado e deduplicar.Reiniciar operação longa.
429 / quotaChamador excedeu política.Respeitar tempo e modelar tráfego.Publicar política legível por máquina.Todos repetirem juntos.
502/503/504Upstream, overload ou gateway transitório.Retry pequeno com jitter; fallback de leitura.Load shed cedo e Retry-After.Retry storm.
409 conflictEstado atual rejeita mudança.Buscar e reconciliar.Problem details e revisão atual.Sobrescrever concorrência.
4xx validação/authRequest ou autoridade deve mudar.Sem retry de transporte.Tipo, campos, correção e request ID.Gastar bateria repetindo.

Idempotência é máquina de estados no servidor

O cliente cria key de alta entropia vinculada a principal e rota. O servidor guarda key, fingerprint, estado, ID da operação/recurso, resultado, timestamps e expiração. Mesma key/payload retorna o outcome original; payload diferente é rejeitado. Duplicatas concorrentes aguardam ou recebem “em andamento”. Persista registro e efeito atomicamente.

Trabalho longo é assíncrono

Retorne 202 Accepted com URL de operação. Exponha pending/running/succeeded/failed/cancelled, timestamps, resultado e problem detail. Faça polling com backoff e ETag ou entregue evento assinado. Não mantenha conexão móvel aberta durante export de minutos.

Paginação começa com ordem estável

Todo list nasce paginado. O cursor vincula query, filtros, sort, snapshot/boundary, direção e última tupla estável, como (updated_at, id). Tokens são opacos e protegidos. Offset serve para conjuntos pequenos/estáticos; coleções mutáveis geram duplicatas e lacunas.

Permita buscar menos

Use page size limitado, field masks, recursos resumidos, filtros, delta sync, updated_since com semântica estável e mídia separada. O cliente precisa carregar a próxima tela acionável, não todo o grafo de domínio.

Compressão é negociada e medida

Suporte Accept-Encoding e Vary: Accept-Encoding. Comprima JSON, texto, protobuf e SVG acima de threshold medido. Não recomprima JPEG/AVIF/vídeo. Compare Brotli, gzip e Zstandard por tamanho, CPU, bateria e latência. Streaming não deve bufferizar tudo.

Cache e revalidação evitam download

Use Cache-Control, ETag, If-None-Match e Last-Modified. Separe conteúdo público e personalizado, configure Vary e mostre freshness. Dados stale só quando regra permitir, com as_of e ações restritas. Cache-Status ajuda no diagnóstico.

Transferências grandes são retomáveis

Upload em partes usa ID, offset/part, checksum, expiração, metadados e finalize explícito. Download usa ranges e validators. Repita apenas partes ausentes. tus é uma opção estabelecida. Não conclua antes de validar tamanho e digest.

Degradação é contrato de produto

Sirva menosPágina menor, summary, sem thumbnail, precisão reduzida, enriquecimento adiado ou cache.
Enfileire intençãoComando local com operation ID, key, versão, expiração, estado e política de conflito.
Bloqueie ação arriscadaSe auth, preço, estoque, saldo ou segurança estão stale, permita leitura e bloqueie write irreversível.
Priorize tráfego centralAuth, segurança, confirmação financeira, metadados de sync e texto antes de analytics e imagem.
Faça load sheddingRejeite trabalho opcional cedo e preserve capacidade crítica.
Mostre estado verdadeiroOffline, sincronizando, pendente, stale, falhou, conflito e confirmado são diferentes.

Use erros legíveis por máquina

RFC 9457 define type, title, status, detail e instance. Adicione código estável, violações, retryability, correlation ID e remediação segura. Não exponha stack nem obrigue parsing de texto traduzido.

Transporte não substitui semântica

HTTP/3 sobre QUIC pode melhorar perda e mudança de conexão; prioridade HTTP sinaliza urgência. Reuso, TLS resumption, edge e menos chamadas sequenciais também ajudam. Nada disso evita duplicidade, lista ilimitada, erro ambíguo ou write stale.

Observe tentativas, não só requests

Trace uma operação lógica por operation ID e request ID por tentativa. Registre timings, bytes, compressão, cache, rede, fase do timeout, retry, idempotência, cursor, stale mode, fila e outcome. Meça amplificação, supressão de duplicatas, conclusão por rede, dados/bateria e p95/p99.

O que eu construiria

SDK compartilhado com deadline, timeouts, classificação, backoff full-jitter, quota, keys, polling, cursor, cache condicional, upload retomável, outbox local, conflitos e telemetria. No servidor: storage de idempotência, problem details, load shedding, paginação, field masks, operações assíncronas, ETags, cancelamento e traces por tentativa.

O princípio

API confiável não finge que a rede é confiável. Torna outcome incerto recuperável, retry limitado, write deduplicado, transferência retomável e estado degradado visível para a próxima decisão correta.

Leituras relacionadas

Artigo sobre APIs confiáveis em redes variáveis, retries, backoff, jitter, idempotência, compressão, paginação, cache, retomada, filas offline e degradação.