Imagine que o usuário toca em Pagar, a conexão cai e o app não recebe a resposta. Sem saber se deu certo, ele toca de novo. Se o servidor tratar as duas requisições como independentes, a pessoa paga duas vezes. A idempotência existe para evitar esse tipo de problema.
O que é idempotência
Uma operação idempotente dá o mesmo efeito, não importa quantas vezes seja executada com os mesmos dados. Definir o status do pedido como pago é idempotente: repetir não muda nada. Somar 10 ao saldo não é: cada repetição soma de novo.
No protocolo HTTP, GET, PUT e DELETE são idempotentes por definição, desde que o servidor siga a regra. O POST, usado para criar coisas, normalmente não é. É nele que o risco de duplicidade aparece.
Quando o problema acontece
- Falha de rede entre o envio e a resposta.
- Clique duplo ou toque repetido em um botão.
- Reenvio automático feito por um cliente HTTP ou fila após erro de tempo esgotado.
- Webhooks entregues mais de uma vez pelo serviço de origem. Veja Webhook: o que é, como funciona e como receber um com segurança.
Como implementar com chave de idempotência
A técnica mais comum é pedir ao cliente que envie, junto com a requisição, um identificador único gerado por ele, chamado de chave de idempotência. Muitas APIs de pagamento usam um cabeçalho para isso.
- O cliente gera um identificador único para aquela operação, como um UUID, e envia na requisição.
- O servidor procura essa chave no banco.
- Se não existe, executa a operação e guarda a chave junto com o resultado.
- Se já existe, não executa de novo e devolve o resultado guardado.
A chave identifica a intenção do usuário, não a requisição. Se ele tentar de novo a mesma ação, reenvie a mesma chave. Uma nova ação pede uma chave nova.
Outras proteções
- No front-end, desative o botão após o primeiro clique e mostre o estado de carregamento.
- Use restrições de unicidade no banco, como um número de pedido único por carrinho.
- Registre logs com a chave para investigar duplicidades depois.
- Defina o que fazer se a mesma chave chegar com dados diferentes: o mais seguro é recusar com erro.
Em cobranças, confira também a documentação do seu provedor de pagamentos, que costuma oferecer suporte próprio à idempotência.