Antes de tudo, o que é ser idempotente?

Nada mais do que garantir que uma transação seja executada uma, e somente uma, única vez — mesmo que uma mesma request seja enviada múltiplas vezes ou ocorram falhas durante o processamento. Ok... mas existem coisas que podemos fazer no front-end para evitar que esse tipo de coisa aconteça?? Siiim, você pode e deve fazer esses tratamentos, como implementar loadings. Mas quem garante que a sua aplicação será utilizada apenas por um browser? Já pensou em alguém chamando o backend via Postman? E se o front-end esquecer de implementar esse tratamento em uma parte crítica do sistema?

Explicando o problema

O problema ocorre quando há duplicação de registros no banco de dados devido ao processamento de uma mesma requisição mais de uma vez. Isso pode acontecer, por exemplo, em situações onde o banco processa um registro e ocorre alguma falha de comunicação entre a API e o client após a gravação dos dados no banco — e o client envia a mesma requisição novamente para o backend... Imagina o usuário clicando duas vezes seguidas no botão de pagamento em um e-commerce. Isso irá gerar um registro duplicado no banco de dados, o que pode causar prejuízos tanto para o usuário quanto para o negócio. Imagina ter que lidar com pedidos duplicados!

Claro, existem alguns tratamentos que o próprio front-end pode (e deve) fazer para evitar tais situações, como implementar loadings. Mas como bem sabemos, quem garante que o seu usuário vai estar usando o browser para chamar o seu backend?! E se, por algum motivo, o front esquecer de fazer esse tratamento em uma parte importante do sistema?!

Image description

Como podemos evitar tal problema?

Uma solução seria atribuir um ID para cada requisição e persistir esse ID em um cache da API. Caso seja enviada uma segunda requisição, a API consulta se o ID da request consta no cache. Se estiver, a requisição não é repassada para o banco. Se o ID não existir no cache, então a requisição é repassada para o banco.

Image description

Como tratar erros no banco?

Caso aconteça algum erro no banco, podemos tomar algumas ações:

  • Simplesmente repassar o erro 500 para o client (e remover o ID do cache);
  • Adicionar a requisição em uma fila para ser reprocessada posteriormente;
  • Implementar algum algoritmo de retry — nesse caso, se o erro do banco for por excesso de carga, os retries podem piorar a situação.

Boas práticas

  • A Idempotency-Key deve ter um TTL (tempo de vida), para evitar acúmulo desnecessário.
  • Considere também incluir o endpoint e o corpo da requisição no hash/verificação para prevenir colisões.
  • Armazene respostas serializadas (ex: JSON) na tabela.
  • Implemente o processo apenas em pontos estratégicos do sistema — não vale a pena implementar em toda requisição. Isso adiciona complexidade e overhead que muitas vezes não trazem benefícios reais. O ideal é ser estratégico e aplicar onde ela realmente faz diferença.

E ai curtiu o post ? Se puder deixa um comentário falando o que achou, é muito importante pra mim 😊

Abraços do Capela

Instagram//Threads : @gui.natan
Linkedin: https://www.linkedin.com/in/guilhermealecrim/