¿Qué es Idempotencia? Métodos HTTP, API Keys, Ejemplos
Idempotencia: llamar a una operación N veces tiene el mismo efecto que una vez, crítico para retries seguros. GET/PUT/DELETE son idempotentes.
¿Qué es idempotencia?
Idempotencia es una propiedad de una operación donde ejecutarla múltiples veces produce el mismo resultado que ejecutarla una sola vez. En notación matemática: f(x) = f(f(x)) = f(f(f(x))). En contextos de APIs y sistemas distribuidos, una operación idempotente puede ser reintentada con seguridad sin causar side effects no intencionados, crítico cuando las redes son no fiables y no sabes si tu request anterior tuvo éxito.
El ejemplo clásico es un botón de elevador: presionarlo una o diez veces produce el mismo resultado (el elevador llega una vez). Compara con cobrar una tarjeta de crédito: presionar "pagar" diez veces sin idempotencia produce diez cargos. El diseño idempotente hace que los sistemas sean seguros para reintentar.
Idempotencia en APIs HTTP/REST
La especificación HTTP (RFC 7231) define qué métodos son idempotentes:
| Método HTTP | ¿Idempotente? | Uso típico |
|---|---|---|
| GET | Sí | Lee un recurso, llamado N veces devuelve los mismos datos, sin cambio de estado |
| HEAD | Sí | Como GET pero solo headers |
| PUT | Sí | Reemplaza un recurso, llamado N veces deja el recurso en el mismo estado final |
| DELETE | Sí | Remueve un recurso. N veces: la primera lo remueve, las siguientes son no-ops |
| OPTIONS | Sí | Descubrir métodos permitidos |
| TRACE | Sí | Loopback diagnóstico |
| POST | No | Crea un recurso, llamado N veces típicamente crea N recursos |
| PATCH | No (por defecto) | Update parcial, depende de semántica |
Nota que idempotente NO significa "devuelve la misma response". DELETE devuelve 204 la primera vez y 404 en subsiguientes, responses diferentes, pero el estado del servidor es idéntico. La propiedad es sobre estado final, no equivalencia de response.
Ejemplos: idempotente vs no-idempotente
Operaciones idempotentes
PUT /users/123 {"name": "Alice"}, setea el nombre del user a Alice. Llamarlo 10 veces deja el nombre como Alice.DELETE /sessions/abc, remueve session abc.GET /products/42, lee producto 42.PUT /flags/feature-x {"enabled": true}, toggle de feature flag por valor absoluto.
Operaciones no-idempotentes
POST /orders {...}, crea una nueva orden. 10 veces crea 10 órdenes.POST /charges {...}, cobra una tarjeta. 10 veces cobra 10 veces.PATCH /counters/x {"increment": 1}, incrementa por 1 cada call.POST /emails {"to": "..."}, envía un email. 10 calls = 10 emails.
Por qué importa la idempotencia
En un mundo single-machine transactional, nunca llamarías la misma operación dos veces. Pero los sistemas modernos son distribuidos, y eso cambia todo:
- Fallas de red. Tu cliente envía un request, no obtiene response. ¿Tuvo éxito? No sabes. Idempotente → reintentas con seguridad.
- Timeouts. Mismo problema. El server puede haber procesado el request después que el cliente se rindió.
- Reintentos distribuidos. Service meshes, load balancers y SDKs auto-reintentan. Solo seguro si upstream es idempotente.
- Arquitecturas basadas en colas. Mensajes pueden ser entregados más de una vez (at-least-once). Consumers deben manejar duplicados idempotentemente.
- Comportamiento de usuarios. Los usuarios doble-clickean botones submit, refrescan páginas mid-request.
Idempotency keys
Para operaciones naturalmente no-idempotentes como crear una orden o cobrar una tarjeta, el patrón estándar es la idempotency key: un identificador único generado por el cliente (típicamente UUID) enviado con cada request. El server registra el resultado indexado por este ID y devuelve el mismo resultado para cualquier request subsecuente con la misma key.
POST /charges
Idempotency-Key: 8e0a4e6b-1b8e-4e3a-b9f7-5e1d3f9c4b8a
{
"amount": 5000,
"currency": "USD"
}El primer call procesa el cargo y guarda el resultado. Calls subsecuentes con la misma key devuelven el resultado guardado sin re-procesar. La key típicamente expira después de un window (ej. 24 horas).
Implementando idempotency keys server-side
- Recibe request con idempotency key.
- Chequea el key store (Redis, tabla DB) por entrada existente.
- Si encontrada: devuelve la response guardada (sin side effects).
- Si no encontrada: adquiere un lock en la key, procesa el request, guarda la response, libera el lock.
- Maneja in-flight requests: si llega un duplicado mientras el primero procesa, espera o devuelve 409 Conflict.
- Expira keys después del window acordado.
Ejemplos del mundo real
- Stripe. La implementación de referencia. Cada endpoint API que cambia estado acepta un header
Idempotency-Key. - AWS SDK. Muchas APIs AWS usan parámetros ClientToken (idempotency keys). EC2 RunInstances, RDS CreateDBInstance.
- PayPal, Square, Adyen. Todos los procesadores de pago usan idempotency keys.
- HTTP/2 + clientes retry-aware. Clientes HTTP modernos auto-reintentan métodos idempotentes en fallas de conexión.
Pitfalls comunes
- Tratar PATCH como siempre idempotente. Depende de semántica.
- Side effects más allá de la base de datos. Si tu endpoint "idempotente" envía un email, llamarlo dos veces envía dos emails.
- Idempotency keys sin expiry. Almacenar cada key forever causa crecimiento ilimitado. Setea TTLs.
- Race conditions en reintentos concurrentes. Usa locks o constraints DB.
- Confundir idempotencia con safety. Safe = sin side effects (GET). Idempotente = N calls = efecto de 1 call. PUT/DELETE son idempotentes pero no safe.
Idempotencia en load testing
- Endpoints POST acumulan estado. Un load test 1000-VU contra POST /orders crea 1000 × duración × rps órdenes. Cleanup después.
- Reuso de idempotency key cachea la response. Si tu script reusa la misma key entre VUs, todos los VUs obtienen la response cacheada.
- Genera idempotency keys únicas por VU/iteración.
- Testea el mecanismo de idempotencia mismo.
FAQ: Idempotencia
¿Es GET siempre idempotente?
Por la spec HTTP, sí. GET nunca debería modificar estado. En la práctica, algunas APIs hacen mal uso de GET para cambios de estado.
¿Es PATCH idempotente?
Depende de la operación. PATCH {set: x} es idempotente. PATCH {increment: 1} no.
¿Cuál es la diferencia entre idempotencia y safety?
Safe significa sin side effects observables (GET, HEAD, OPTIONS). Idempotente significa N calls = estado final de 1 call. PUT y DELETE son idempotentes pero no safe.
¿Cómo hago POST idempotente?
Usa una idempotency key, un ID único generado por cliente (UUID) enviado con cada request.
¿Qué es un buen TTL de idempotency key?
Stripe usa 24 horas. Para APIs high-throughput, 1 hora puede ser suficiente. Para APIs de pago low-throughput, 7-30 días dan más tolerancia de retry.
¿Aplica idempotencia a gRPC y GraphQL?
Sí. Las definiciones de método gRPC pueden especificar nivel de idempotencia. Operaciones GraphQL Query son idempotentes por convención; Mutations necesitan diseño explícito de idempotencia.
Prueba LoadFocus para testear idempotencia at scale
Si estás diseñando un mecanismo de idempotencia y quieres verificarlo bajo carga (reintentos concurrentes, race conditions, expiry de keys), LoadFocus corre scripts JMeter y k6 desde 25+ regiones cloud con hasta 12.500 VUs. Regístrate en loadfocus.com/signup, sin tarjeta de crédito, y corre tu primer stress test de idempotencia en menos de 5 minutos.
Herramientas LoadFocus relacionadas
Lleva este concepto a la práctica con LoadFocus, la misma plataforma que potencia todo lo que acabas de leer.