¿Qué es la idempotencia? Métodos HTTP, idempotency keys, ejemplos
Idempotencia: repetir una operación deja el mismo estado que hacerla una vez. Qué métodos HTTP lo cumplen y cómo las keys hacen seguro reintentar POST.
¿Qué es la idempotencia?
Una operación es idempotente si ejecutarla varias veces deja el sistema en el mismo estado que ejecutarla una sola vez. En HTTP, eso significa que un cliente puede repetir una solicitud tras un timeout o una conexión cortada sin provocar un segundo cobro, pedido o correo. GET, PUT y DELETE son idempotentes por definición. POST no lo es.
La imagen habitual es el botón del ascensor: pulsarlo diez veces sigue trayendo un solo ascensor. Un botón de "pagar" sin protección es lo contrario, y diez pulsaciones pueden ser diez cobros. Un diseño idempotente hace seguros los reintentos.
Idempotencia en los métodos HTTP
La RFC 9110 (que sustituyó a la RFC 7231) establece que PUT, DELETE y todos los métodos seguros son idempotentes:
| Método | ¿Idempotente? | Por qué |
|---|---|---|
| GET, HEAD, OPTIONS, TRACE | Sí | Métodos seguros: leen y no cambian el estado |
| PUT | Sí | Reemplaza el recurso por la misma representación cada vez |
| DELETE | Sí | La primera llamada elimina el recurso y las siguientes no encuentran nada que eliminar |
| POST | No | Normalmente crea un recurso nuevo o dispara una acción en cada llamada |
| PATCH | No garantizado | Depende del parche: fijar un valor es idempotente, incrementar no |
Idempotente no significa "devuelve la misma respuesta". Un primer DELETE puede devolver 204 y una repetición 404, y aun así el estado del servidor es idéntico. La propiedad describe el efecto buscado sobre el servidor, no la respuesta. La RFC 5789 señala que una solicitud PATCH puede plantearse de forma que sea idempotente.
Ejemplos
PUT /users/123con{"name": "Alice"}fija el nombre en Alice. Diez llamadas, el mismo resultado.DELETE /sessions/abcno deja ninguna sesión abc, por muchas veces que lo llames.POST /orderscrea un pedido nuevo cada vez, así que diez llamadas hacen diez pedidos.PATCH /counters/xcon{"increment": 1}suma uno cada vez. No es idempotente.POST /emailsenvía un mensaje por llamada. Un efecto secundario fuera de tu base de datos también cuenta.
Por qué importa la idempotencia
- Timeouts y conexiones cortadas. El cliente no puede saber si el servidor procesó la solicitud antes de que fallara la conexión. Con una operación idempotente, simplemente reintenta.
- Reintentos automáticos. La RFC 9110 permite que los clientes reintenten automáticamente solicitudes idempotentes tras un fallo de conexión, y prohíbe que un proxy reintente automáticamente una no idempotente. Los SDK y los service meshes siguen reglas parecidas.
- Entrega at-least-once. Las colas y los webhooks pueden entregar el mismo mensaje más de una vez, así que el receptor debe tolerar duplicados.
- Las personas. Los usuarios hacen doble clic en enviar y recargan páginas a medias.
Idempotency keys
Para operaciones que no son idempotentes por naturaleza, como crear un pedido o cobrar una tarjeta, el patrón habitual es una idempotency key (clave de idempotencia): un valor único que el cliente genera para una operación lógica y envía en cada intento de ella.
POST /charges HTTP/1.1
Idempotency-Key: 8e0a4e6b-1b8e-4e3a-b9f7-5e1d3f9c4b8a
Content-Type: application/json
{"amount": 5000, "currency": "usd"}El servidor guarda el resultado bajo esa clave. Una repetición con la misma clave devuelve el resultado guardado en lugar de ejecutar de nuevo la operación. Stripe es el ejemplo más conocido y documenta los detalles: la cabecera Idempotency-Key, claves de hasta 255 caracteres, UUID V4 como recomendación y, en la API v1, el código de estado y el cuerpo de la primera solicitud se guardan y se reproducen, incluidos los errores 500. Las claves pueden eliminarse pasadas al menos 24 horas, y reutilizar una clave con parámetros distintos devuelve un error. Stripe no necesita claves en GET ni en DELETE, porque ya son idempotentes.
Un borrador del IETF (draft-ietf-httpapi-idempotency-key-header) trabaja para estandarizar la cabecera Idempotency-Key. Sigue siendo un Internet-Draft, no una RFC. Describe una respuesta 409 cuando llega un reintento mientras la solicitud original aún se ejecuta, y una 422 cuando se reutiliza una clave con otro payload.
Implementar las claves en el servidor
- Lee la clave de la solicitud y guárdala junto con una huella del cuerpo de la solicitud.
- Busca la clave. Si existe un resultado terminado y la huella coincide, devuélvelo sin efectos secundarios.
- Si la huella difiere, rechaza la solicitud (422 en el borrador).
- Si no hay entrada, registra la clave como en curso, ejecuta la operación, guarda la respuesta y márcala como terminada. Una restricción de unicidad sobre la columna de la clave evita que dos solicitudes concurrentes se ejecuten ambas.
- Si la clave está en curso, espera o devuelve 409.
- Caduca las claves tras una ventana fija para que el almacenamiento no crezca sin límite.
Errores habituales
- Suponer que PATCH es idempotente.
{"set": 5}lo es;{"increment": 1}no. - Una clave nueva por reintento. La clave pertenece a la operación, no al intento. Si cada reintento genera una clave nueva, no se deduplica nada.
- Olvidar los efectos secundarios fuera de la base de datos. Un endpoint "idempotente" que envía un correo en cada llamada no es idempotente.
- Sin caducidad. Guardar cada clave para siempre hace crecer el almacenamiento sin límite. Elige una ventana que cubra los reintentos de tus clientes.
- Condiciones de carrera. Dos solicitudes simultáneas con una misma clave pueden ejecutarse ambas si no bloqueas o no usas una restricción de unicidad.
- Confundir seguro con idempotente. Seguro significa sin cambio de estado (GET). PUT y DELETE son idempotentes pero no seguros.
Idempotencia en pruebas de carga y monitorización
- Los endpoints no idempotentes acumulan datos. Una prueba con POST crea registros en cada iteración, así que planifica la limpieza o usa un entorno de pruebas. Con un intervalo de 5 minutos, una comprobación de monitorización que hace POST se ejecuta 288 veces al día, por lo que conviene una comprobación de solo lectura o un endpoint de pruebas dedicado.
- Genera una clave única por usuario virtual e iteración. Si todos los usuarios virtuales reutilizan una clave, todos reciben la primera respuesta guardada y tu prueba solo cargó la primera solicitud.
- Prueba el propio mecanismo. Envía la misma solicitud dos veces, y también a la vez, y comprueba que las respuestas coinciden y que solo existe un registro. Consulta pruebas de API.
- Vigila los reintentos bajo carga. Los clientes que reintentan tras un timeout añaden tráfico justo cuando el servidor va lento, y así se llega, entre otras cosas, a los límites de tasa (consulta Common Causes of API Rate Limiting, en inglés).
LoadFocus ejecuta scripts de JMeter y k6 desde 25 regiones en la nube (pruebas de carga), lo que encaja con pruebas de reintentos concurrentes. Para dar a cada usuario virtual sus propias claves, consulta data-driven load testing scripts, y para una primera prueba de API, Load Testing RESTful APIs with LoadFocus (ambos en inglés). Para comprobaciones programadas de solo lectura, está la monitorización de API. Los verbos CRUD que hay detrás de estas reglas se explican en operaciones CRUD.
Preguntas frecuentes sobre idempotencia
¿Es GET siempre idempotente?
Por definición sí: GET es un método seguro y no debería cambiar el estado. Algunas APIs usan GET de forma indebida para acciones como el seguimiento o la baja, lo que rompe la regla y permite que la precarga y los reintentos disparen la acción.
¿Es PATCH idempotente?
No por definición. Depende de la operación: fijar un campo a un valor es idempotente, incrementar un contador no.
¿Qué diferencia hay entre idempotente y seguro?
Seguro significa que la solicitud no pretende cambiar el estado del servidor (GET, HEAD, OPTIONS). Idempotente significa que repetirla tiene el mismo efecto buscado que enviarla una vez. PUT y DELETE son idempotentes pero no seguros.
¿Cómo hago idempotente una solicitud POST?
Envía una idempotency key, un valor único para la operación que reutilizas en cada reintento. El servidor guarda el primer resultado bajo esa clave y lo devuelve en las repeticiones.
¿Cuánto debe durar una idempotency key?
Lo suficiente para cubrir la ventana de reintentos de tus clientes. Stripe elimina las claves en la API v1 pasadas al menos 24 horas. Elige tu propia ventana y documéntala.
¿Se aplica la idempotencia a GraphQL y gRPC?
Sí. Las queries de GraphQL leen datos, mientras que las mutaciones necesitan su propia protección, por ejemplo una clave en el input. gRPC permite marcar un método como idempotente en su definición, lo que indica a los clientes cuándo es seguro reintentar.
Términos relacionados
- ¿Qué es JSON? Guía para principiantes con sintaxis y ejemplos
- ¿Qué es JSON-RPC? Protocolo, ejemplos y comparación con REST
- ¿Qué es multipart/form-data Content-Type? Subida de archivos, ejemplos
- ¿Qué es Swagger? Swagger y OpenAPI explicados
- Operaciones CRUD: Create, Read, Update, Delete explicado
- ¿Qué son los ataques a APIs?
- ¿Qué son las cookies de API? Definición y seguridad
- Métricas de rendimiento de API: latencia, throughput y tasa de errores
Herramientas LoadFocus relacionadas
Lleva este concepto a la práctica con LoadFocus, la misma plataforma que potencia todo lo que acabas de leer.