Saltar para o conteúdo
← Ideias

Idempotência em APIs: como evitar duplicidades sem ocultar erros

Uma chave idempotente permite repetir operações sensíveis sem duplicar seus efeitos. Saiba como definir seu escopo, lidar com a concorrência e responder a erros.

Diagrama de uma API que usa uma chave idempotente para reconhecer novas tentativas e evitar a duplicação de uma operação.

Uma solicitação pode chegar ao servidor sem que o cliente receba a resposta. Talvez o tempo limite se esgote depois que um pagamento é registrado ou um pedido é criado. Se o cliente repetir a solicitação sem verificar o que aconteceu, o sistema poderá executar a operação novamente. A idempotência em APIs ajuda a evitar esse resultado: ela permite reconhecer que várias solicitações correspondem à mesma tentativa de negócio e limitar efeitos duplicados.

Mas não basta adicionar um cabeçalho com uma chave. É preciso decidir quem a gera, por quanto tempo ela é válida, qual resposta será repetida e como coordenar gravações locais com serviços externos. O objetivo não é ocultar erros nem prometer uma execução exatamente uma vez; é tornar as novas tentativas seguras sob condições explícitas.

O que significa idempotência e que problema ela resolve

O que significa idempotência e que problema ela resolve

Uma operação é idempotente quando repeti-la com os mesmos dados não altera o resultado final depois da primeira execução. Por exemplo, definir o endereço de entrega de um pedido como um valor específico pode ser idempotente: aplicar a mesma atualização duas vezes deixa o recurso no mesmo estado que uma única aplicação.

Já uma operação como “adicionar uma unidade ao carrinho” não é idempotente por si só: repeti-la pode aumentar a quantidade duas vezes. Criar um pedido ou registrar uma cobrança também pode produzir efeitos adicionais se cada solicitação for interpretada como uma nova intenção. Nessas operações, uma chave idempotente pode associar as novas tentativas à mesma tentativa lógica.

Idempotência não significa que todas as respostas serão idênticas nem que a solicitação nunca falhará. Significa controlar os efeitos da repetição de acordo com um contrato. O cliente pode receber um erro e, ao tentar novamente, obter o resultado já registrado; ou pode receber outra vez um erro definitivo. O importante é que o servidor não execute inadvertidamente um segundo efeito.

Quando adicionar idempotência e quando ela é desnecessária

O risco surge quando uma operação tem efeitos relevantes e o cliente não consegue saber com certeza se o servidor a concluiu. Uma resposta perdida, um timeout, uma desconexão ou uma nova tentativa automática podem deixar o resultado ambíguo. Isso é especialmente sensível ao criar pedidos, iniciar pagamentos, reservar estoque ou processar solicitações.

Antes de adicionar chaves, revise o contrato existente. Uma atualização que define um estado específico pode ser idempotente por projeto. Uma consulta de leitura normalmente não cria esse problema. Por outro lado, um endpoint que gera um novo recurso ou movimento a cada chamada precisa de uma estratégia clara se seus consumidores puderem repetir a solicitação.

A idempotência tem custos: armazenamento de chaves e resultados, regras de expiração, gestão de concorrência e mais cenários para testar. Não a adicione indiscriminadamente a todos os endpoints. Priorize os casos em que três sinais aparecem juntos:

  • A operação pode produzir um efeito duplicado difícil ou caro de reverter.
  • O cliente ou a infraestrutura repete a solicitação diante de falhas transitórias.
  • Uma resposta perdida impede saber se a operação foi concluída.

Defina também o que significa “mesma tentativa” para o negócio. Duas compras intencionais e iguais não devem ser confundidas apenas por terem o mesmo valor e conteúdo. A deduplicação deve se basear em uma chave da tentativa, não em uma suposição de que solicitações semelhantes representam a mesma intenção.

Como projetar uma chave: origem, unicidade, escopo e duração

Em geral, o cliente gera uma chave única para cada operação lógica e a mantém em todas as novas tentativas. Ela pode ser enviada em um cabeçalho acordado ou no corpo da solicitação, desde que o contrato seja explícito. Se o cliente gerar uma chave nova a cada tentativa, o servidor não conseguirá relacioná-las. Se reutilizar uma chave em uma nova compra, o servidor poderá bloquear uma intenção legítima.

A chave identifica a tentativa, mas não substitui autenticação nem autorização. Ela deve estar vinculada a um escopo, como a conta ou o estabelecimento autenticado e o tipo de operação. Assim, uma coincidência acidental entre dois clientes não mistura os resultados. O servidor deve verificar esses limites em cada solicitação.

Armazene também uma impressão digital da solicitação normalizada: os campos que determinam o efeito, com regras estáveis para valores padrão e representação. Se uma chave já existir e chegar uma solicitação com conteúdo incompatível, rejeite-a como conflito; não a trate como uma nova tentativa válida nem execute o conteúdo recebido. A impressão digital deve excluir dados irrelevantes, mas incluir detalhes que alterem a intenção, como valor ou moeda.

A duração depende do comportamento dos clientes, das filas e dos processos de recuperação. Uma janela curta demais permite que uma nova tentativa tardia repita o efeito; uma janela longa demais acumula registros e pode impedir reutilizações legítimas. Defina um período alinhado ao prazo máximo razoável para novas tentativas e informe o que acontece depois. Em operações financeiras ou de alto impacto, talvez seja necessário manter uma referência durável do resultado além da janela operacional.

Respostas para chaves repetidas e solicitações em andamento

O contrato deve distinguir vários casos. Se a chave já foi concluída e a impressão digital corresponde, o servidor pode devolver o resultado armazenado da operação original. Isso costuma incluir o código e o corpo relevantes, mas não necessariamente todos os cabeçalhos de transporte. A resposta deve permitir que o cliente identifique o recurso criado ou o estado alcançado.

Se a chave estiver em uso, evite iniciar uma segunda execução. Você pode responder com um estado que indique que o processamento continua ou com um conflito temporário que oriente o cliente a consultar o resultado ou tentar novamente mais tarde. O cliente precisa de uma regra clara: quanto esperar, se deve manter a mesma chave e como obter o resultado final. Não informe sucesso para uma operação que ainda não foi confirmada.

Se a chave existir com uma impressão digital diferente, devolva um erro explícito e não altere o registro original. Se a primeira execução falhou, defina quais falhas serão armazenadas como resultado terminal e quais permitem um novo processamento. Por exemplo, um erro de validação pode ser definitivo para aquela solicitação, enquanto uma interrupção antes da confirmação dos efeitos pode permitir a recuperação. Não há uma política universal: ela deve refletir o ponto em que o sistema consegue demonstrar o que aconteceu.

Persistência, concorrência e efeitos em outros sistemas

A reserva da chave e a criação do efeito local devem ser coordenadas atomicamente quando compartilham um banco de dados. Uma restrição de unicidade sobre o escopo e a chave ajuda a impedir que duas solicitações simultâneas passem pela mesma verificação inicial. A lógica deve tratar a colisão e ler o estado criado pela solicitação vencedora, em vez de depender apenas da sequência “consultar e depois inserir”.

Armazene estados compreensíveis, por exemplo: em andamento, concluído e falha recuperável ou definitiva. Inclua registros de data e hora e uma política de recuperação para casos em que o processo foi interrompido. Um bloqueio que nunca expira pode deixar operações travadas; um bloqueio que expira sem controle pode permitir que dois processos atuem ao mesmo tempo. Antes de retomar uma operação, a recuperação deve verificar o estado do efeito.

A transação local não inclui automaticamente um provedor de pagamentos nem outro serviço remoto. Se o sistema salvar o pedido e falhar antes de chamar o provedor, ou se o provedor processar o pagamento e a resposta se perder, será preciso reconciliar os estados. Quando fizer sentido, use uma caixa de saída transacional para publicar o trabalho depois de confirmar a alteração local e propague uma referência estável ao sistema externo, se ele oferecer suporte à deduplicação. Registre identificadores externos e considere consultas ou conciliações.

Não prometa “exatamente uma vez” de ponta a ponta apenas porque existe uma chave. Podem ocorrer falhas ambíguas entre redes, bancos de dados e provedores. A garantia real deve descrever quais efeitos são deduplicados, em qual escopo, por quanto tempo e quais casos exigem intervenção ou conciliação.

Erros comuns e lista de verificação

Erros comuns e lista de verificação
  • Gerar uma chave nova a cada tentativa: o cliente deve persistir e reutilizar a chave da tentativa original.
  • Usar uma chave global sem escopo: associe-a ao cliente autenticado e à operação pertinente.
  • Reutilizar a chave com conteúdo diferente: compare uma impressão digital e rejeite a reutilização incompatível.
  • Definir a expiração sem analisar tentativas tardias: documente a janela e decida como recuperar operações antigas.
  • Dar uma resposta ambígua em caso de concorrência: especifique como consultar ou tentar novamente enquanto a primeira solicitação continua ativa.
  • Confiar que a chave cobre sistemas externos: incorpore referências, conciliação e tratamento de falhas parciais.

Antes de publicar o endpoint, verifique se o cliente gera uma chave por intenção e a mantém após um timeout; se duas solicitações simultâneas com a mesma chave não duplicam o efeito; e se uma mesma chave com dados diferentes não executa uma nova operação. Teste também falhas antes e depois da gravação, reinicializações do processo, expiração e respostas perdidas.

Por fim, monitore métricas de chaves repetidas, conflitos de impressão digital, operações travadas e divergências com serviços externos. Esses sinais ajudam a detectar erros de integração e ajustar o período de retenção. Uma implementação útil não elimina as falhas: deixa explícito o que pode ser repetido sem duplicar efeitos e oferece um caminho seguro para resolver o que continuar incerto.

Fuentes y referencias

  1. Web standardsW3C
  2. OWASP Cheat Sheet SeriesOWASP Foundation
  3. Web performanceweb.dev