Cómo diseñar APIs REST idempotentes y versionadas

Backend2026-09-17TryQuickToolBox

Despliegas una nueva función y, de repente, tu API recibe peticiones POST duplicadas de clientes que reintentan tras un timeout. Tu base de datos ahora tiene dos pedidos idénticos. O lanzas un cambio incompatible y las apps móviles fallan porque esperaban el formato de respuesta anterior. Estos son dos de los problemas más comunes y dolorosos en el diseño de APIs: operaciones no idempotentes y cambios incompatibles. Esta guía te muestra cómo resolver ambos con patrones prácticos de idempotencia y versionado en APIs REST.

Por qué importa la idempotencia en las APIs REST

Idempotencia significa que hacer la misma petición varias veces tiene el mismo efecto que hacerla una sola vez. Los métodos HTTP tienen semánticas de idempotencia definidas: GET, HEAD, PUT, DELETE y OPTIONS son idempotentes, mientras que POST y PATCH no lo son. Pero las APIs del mundo real a menudo necesitan aceptar POST para operaciones como crear recursos o procesar pagos. Los fallos de red, los timeouts de los clientes y la lógica de reintentos pueden causar duplicados. Sin idempotencia, te arriesgas a cargos duplicados, registros duplicados o un estado inconsistente.

Técnicas para APIs REST idempotentes

1. Usa claves de idempotencia para peticiones POST

El enfoque más común es permitir que los clientes envíen una clave única (por ejemplo, un UUID) en una cabecera Idempotency-Key. El servidor almacena la clave y el resultado de la operación. Si recibe la misma clave de nuevo, el servidor devuelve el resultado almacenado en lugar de reejecutar la operación.

POST /payments
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json

{
  "amount": 1000,
  "currency": "USD"
}

Pasos de implementación:

  1. El cliente genera una clave única (UUID v4) para cada operación lógica.
  2. El servidor comprueba si la clave existe en un almacén persistente (por ejemplo, Redis o una base de datos).
  3. Si no existe, procesa la petición y almacena la clave con el estado y el cuerpo de la respuesta.
  4. Si existe, devuelve la respuesta almacenada sin volver a procesarla.

Establece una expiración razonable (por ejemplo, 24 horas) para evitar un crecimiento ilimitado del almacenamiento.

2. Aprovecha las peticiones condicionales

Para las actualizaciones, usa las cabeceras ETag e If-Match para evitar actualizaciones perdidas. El servidor devuelve un ETag que representa el estado actual. El cliente lo reenvía con If-Match; si el recurso ha cambiado, el servidor devuelve 412 Precondition Failed. Esto hace que las peticiones PUT sean seguras frente a condiciones de carrera.

PUT /articles/123
If-Match: "abc123"
Content-Type: application/json

{"title": "Updated title"}

3. Diseña PUT para una idempotencia natural

Prefiere PUT sobre POST cuando el cliente pueda determinar la URL del recurso. Por ejemplo, PUT /users/{userId} es naturalmente idempotente porque las llamadas repetidas sobrescriben el mismo recurso. Usa POST solo cuando el servidor asigne el ID.

4. Gestiona la detección de duplicados con restricciones únicas

Combina las claves de idempotencia con restricciones únicas en la base de datos sobre claves de negocio (por ejemplo, el número de pedido). Si un duplicado se cuela, la base de datos lo rechaza y puedes devolver un 409 Conflict con un mensaje claro.

Estrategias de versionado para APIs REST

Las APIs evolucionan. Campos nuevos, comportamiento modificado o endpoints eliminados pueden romper a los clientes existentes. El versionado te permite introducir cambios sin interrumpirlos. Existen varias estrategias comunes:

Estrategia Ejemplo Ventajas Inconvenientes
Ruta URI /v1/users Explícito, fácil de enrutar, compatible con caché Las URLs cambian, puede generar desorden
Parámetro de consulta /users?version=1 Simple, opcional Fácil de omitir, no es RESTful
Cabecera personalizada Accept-Version: v1 Mantiene las URLs limpias Más difícil de probar en el navegador
Tipo de medio Accept: application/vnd.api.v1+json Negociación de contenido, REST puro Complejo, menos común

Para la mayoría de los equipos, el versionado por ruta URI es la opción más pragmática. Es visible, fácil de documentar y funciona bien con API gateways y CDNs.

Cómo versionar sin romper a los clientes

  1. Empieza con v1 en la ruta desde el primer día. Añadir versionado más tarde es más difícil.
  2. Solo cambios aditivos dentro de una versión: nuevos campos opcionales, nuevos endpoints. Nunca elimines ni renombres campos.
  3. Deprecia con elegancia: anuncia el fin de vida, proporciona guías de migración y monitoriza el uso de las versiones antiguas.
  4. Usa cabeceras sunset: Sunset: Sat, 31 Dec 2025 23:59:59 GMT para informar a los clientes.
  5. Mantén como máximo dos versiones activas para limitar la carga de mantenimiento.

Poniéndolo todo junto: un ejemplo práctico

Considera una API de pagos. Quieres crear un pago de forma idempotente y versionar el endpoint.

POST /v1/payments
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json

{
  "amount": 1000,
  "currency": "USD"
}

Lógica del servidor:

Para las actualizaciones, usa PUT con ETag:

PUT /v1/payments/123
If-Match: "xyz789"
Content-Type: application/json

{"amount": 1500}

Si el ETag no coincide, devuelve 412. Esto evita sobrescribir cambios concurrentes.

Errores comunes y cómo evitarlos

Preguntas frecuentes

¿Qué es una API REST idempotente?

Una API REST idempotente garantiza que hacer la misma petición varias veces produce el mismo resultado que hacerla una sola vez. Esto es crucial para gestionar reintentos de forma segura, especialmente en métodos no idempotentes como POST.

¿Qué métodos HTTP son idempotentes?

GET, HEAD, PUT, DELETE, OPTIONS y TRACE son idempotentes. POST y PATCH no son idempotentes por defecto, pero puedes hacerlos idempotentes usando técnicas como las claves de idempotencia.

¿Cuál es la mejor forma de versionar una API REST?

El versionado por ruta URI (por ejemplo, /v1/users) es el enfoque más común y práctico. Es explícito, fácil de enrutar y funciona bien con caché y API gateways. Otras opciones incluyen parámetros de consulta, cabeceras personalizadas y tipos de medio, pero tienen sus compromisos.

¿Listo para probar las respuestas JSON de tu API? Usa nuestro JSON Formatter para validar y formatear payloads rápidamente.