Idempotência: o detalhe que separa APIs frágeis das confiáveis

Tem vídeo desse conteúdo no canal Veja o passo a passo completo em vídeo.
Assistir no YouTube →
Idempotência: o detalhe que separa APIs frágeis das confiáveis

Imagine que um cliente clica em “pagar”. A requisição sai do celular dele, atravessa uma rede de celular instável, e… nada. A tela fica girando. Ele não sabe se a cobrança passou ou não. O que ele faz? Clica de novo. Claro que clica.

Se o seu backend não estiver preparado para isso, você acabou de cobrar duas vezes a mesma pessoa. E esse é, em uma frase, o problema que a idempotência resolve.

O que idempotência quer dizer, sem o palavrão

Uma operação é idempotente quando executá-la uma vez ou várias vezes dá exatamente o mesmo resultado. Apertar o botão do elevador dez vezes não faz ele chegar mais rápido — ele já foi chamado na primeira. Isso é idempotência no mundo real.

No HTTP, alguns métodos já são idempotentes por definição. Um GET não muda nada. Um PUT que define o estado completo de um recurso pode ser repetido à vontade — o resultado final é o mesmo. O problema mora no POST, que normalmente cria algo novo a cada chamada. Repetir um POST de pagamento é repetir a cobrança.

Por que “é só não repetir a requisição” não funciona

A tentação é dizer: “o cliente que não clique duas vezes”. Mas a repetição raramente é culpa do usuário. Ela é estrutural. A rede caiu depois que o servidor processou, mas antes da resposta chegar. O cliente tem um retry automático. Um balanceador reenviou a requisição. Uma fila entregou a mesma mensagem duas vezes porque garante “pelo menos uma entrega”.

Em sistemas distribuídos, a duplicata não é exceção — é uma certeza estatística. Mais cedo ou mais tarde, a mesma operação vai chegar duas vezes. A pergunta não é “se”, é “o que meu sistema faz quando isso acontecer”.

A chave de idempotência, na prática

A solução mais usada — a mesma que gateways de pagamento como o Stripe adotam — é a chave de idempotência. O cliente gera um identificador único para aquela operação e manda junto num cabeçalho:

POST /pagamentos
Idempotency-Key: 3a1f9c8e-7b2d-4e5a-9f10-c2d4e6f8a0b1

{ "valor": 4990, "pedido_id": "P-2026-88" }

Do lado do servidor, a lógica é direta:

  • Chegou uma requisição com uma chave. O servidor pergunta ao banco: “já vi essa chave antes?”.
  • Se não: processa a operação, salva o resultado junto com a chave e responde.
  • Se sim: não processa de novo. Apenas devolve a resposta que já foi guardada da primeira vez.

O cliente que clicou três vezes recebe três respostas idênticas e é cobrado uma vez só. Do ponto de vista dele, funcionou de primeira — que é exatamente a ilusão que a gente quer criar.

Os detalhes que separam o conceito da implementação sólida

O desenho acima é simples no papel e tem duas armadilhas na vida real.

A primeira é a corrida entre requisições duplicadas simultâneas. Se as duas cópias chegam quase ao mesmo tempo, ambas podem verificar “não existe” antes de qualquer uma gravar. A saída é deixar o banco resolver: uma restrição de unicidade na coluna da chave faz a segunda inserção falhar, e você trata esse erro como “operação já em andamento”.

CREATE UNIQUE INDEX idx_idem
  ON operacoes (idempotency_key);
-- A segunda tentativa de INSERT com a mesma chave
-- estoura violação de unicidade. Você a converte
-- em "aguarde, já estamos processando".

A segunda é o tempo de vida da chave. Guardar chaves para sempre incha o banco. O comum é dar um prazo de validade — 24 horas costuma ser suficiente para cobrir retentativas, sem virar um depósito eterno.

Idempotência não é sobre impedir a duplicata de chegar. É sobre fazer com que, quando ela chegar, não cause estrago.

Idempotência também vive nos verbos HTTP

Vale entender por que o próprio HTTP já pensa nisso. Um PUT e um DELETE são idempotentes por definição: repetir “defina o nome como João” ou “apague o pedido 88” leva ao mesmo estado final, não importa quantas vezes você mande. Isso não é detalhe acadêmico — é o que permite a clientes, proxies e bibliotecas reenviarem essas requisições com segurança quando a rede engasga.

O mal-entendido comum é achar que idempotente quer dizer “retorna sempre a mesma resposta”. Não é bem isso. O segundo DELETE pode responder 404 em vez de 200, e tudo bem — o que importa é que o efeito no sistema é o mesmo: o pedido continua apagado. Foque no estado final, não no código de status.

É por isso que retentativas automáticas combinam naturalmente com esses verbos, e por que o POST precisa da chave de idempotência para entrar nessa festa com a mesma segurança.

Onde isso importa (e onde não)

Nem toda rota precisa disso. Um endpoint que atualiza o nome do usuário é naturalmente seguro de repetir — o estado final é o mesmo. O cuidado vale para operações que criam efeitos colaterais: cobranças, envio de e-mail, criação de pedidos, transferências, disparo de notificações.

Se você está construindo qualquer coisa que mexe com dinheiro ou dispara ações no mundo real, tratar idempotência deixa de ser refinamento e passa a ser requisito. É o tipo de detalhe invisível quando está certo e absolutamente visível quando falta — geralmente na forma de um cliente irritado perguntando por que foi cobrado duas vezes.

Leia também

Prefere ver em vídeo?

Esse artigo virou um vídeo completo no canal, com diagramas animados e demo ao vivo.

Assistir no YouTube →