Una API parece sencilla mientras todo sale bien: el cliente envía JSON, el servidor modifica algo y devuelve otro JSON. La dificultad aparece cuando dos clientes editan a la vez, una respuesta se pierde, un identificador pertenece a otro tenant o una operación tarda más que la conexión. En esos casos, la forma de la URL importa menos que el contrato que permite responder cuatro preguntas: qué objeto lógico se manipula, quién puede hacerlo, qué efecto promete la operación y qué sabe cada actor después de un fallo.
El capítulo anterior separó políticas del navegador de autorización del servidor. Aquí continuamos desde esa frontera. CORS puede decidir si un script observa una respuesta, pero no define el recurso ni concede acceso. OpenAPI puede describir una operación, pero la descripción no ejecuta sus controles. Un token puede autenticar a una persona, pero no autoriza automáticamente cada objeto cuyo identificador conozca. La API defendible surge de relacionar semántica, autoridad, concurrencia y evidencia.
Una API es un contrato, no una colección de rutas
Una interfaz de programación de aplicaciones ofrece operaciones observables a consumidores. En una API HTTP, esas operaciones se expresan mediante mensajes: método, URI de destino, campos, contenido y una respuesta con status, campos y quizá contenido. HTTP aporta semántica compartida, pero el dominio debe precisar qué significa crear una reserva, cerrar una cuenta o aprobar una solicitud.
El contrato incluye mucho más que el caso feliz:
- qué entradas son válidas y cómo se normalizan;
- qué identidad y autoridad se requieren;
- qué precondiciones deben cumplirse;
- qué efecto se solicita y si puede repetirse;
- qué respuesta significa éxito, rechazo, conflicto o aceptación diferida;
- qué permanece cierto si hay concurrencia, timeout o reintento;
- qué versiones y representaciones admite cada extremo.
Una especificación OpenAPI es útil para registrar paths, operaciones, parámetros, esquemas, respuestas y requisitos declarados. Puede alimentar documentación, clientes, validadores y pruebas. No demuestra que el runtime corresponda a la descripción. Tampoco prueba que la autorización se ejecute después de resolver el objeto, que una transacción cubra todo el efecto o que una respuesta perdida sea recuperable. El documento y la implementación necesitan pruebas de conformidad; ninguno sustituye al otro.
La calidad de una API no se mide por parecerse a una plantilla REST. Una interfaz puede usar recursos con rigor y aun exponer operaciones de dominio que no son CRUD. POST /loans/17/approvals puede representar la creación de una decisión subordinada; POST /loans/17:approve puede hacer explícita una acción. La elección debe conservar semántica, autorización y evolución, no obedecer a una estética de sustantivos a costa de ocultar el modelo.
Recurso, representación y persistencia
RFC 9110 llama recurso al objetivo de un request. HTTP no limita su naturaleza: puede ser un documento, una colección, el estado de un proceso, una vista calculada o una función temporal como «el clima actual». La URI lo identifica dentro del contrato. No revela necesariamente dónde ni cómo se almacena.
Una representación es información comunicable que refleja un estado pasado, actual o deseado de ese recurso. Consta de metadatos y datos. El JSON recibido no es «el recurso viajando por la red»; es una representación seleccionada. El mismo recurso puede ofrecer JSON, HTML o una forma comprimida, puede variar por idioma y puede omitir campos que el consumidor no está autorizado a ver.
La persistencia es una decisión interna. Un recurso puede agregarse desde varias tablas, derivarse de eventos, consultar otro servicio o no tener almacenamiento estable. A la inversa, una fila puede contribuir a varias representaciones. Vincular públicamente cada URI a una tabla y cada propiedad a una columna hace que decisiones internas se conviertan en compatibilidad externa.
Esta separación evita tres errores comunes:
- «La URI es una ruta a la base de datos». No: identifica el objetivo de la operación. Resolverlo puede exigir contexto, versión, tenant y reglas de dominio.
- «El JSON es la verdad completa». No: es una representación producida para un principal y un instante; puede ser parcial, derivada o negociada.
- «Si conozco el ID, poseo el objeto». No: identificación y autorización son decisiones distintas.
Vista adaptada. Toca el diagrama para ampliarlo.
Considera GET /accounts/42. El 42 ayuda a seleccionar un recurso, pero la decisión defendible necesita al menos el principal autenticado, la acción read, el tenant activo, la relación con la cuenta y el estado del objeto. El servidor puede devolver una representación sin datos internos, mapear la cuenta a varias fuentes y registrar una decisión. Nada de eso convierte la URI en permiso ni la cuenta en una fila concreta.
El método lleva semántica
HTTP separa identificación y operación: la URI identifica el recurso y el método expresa la semántica solicitada. Por eso GET /documents/7?do=delete es peligroso. Aunque el parámetro diga «delete», el método GET sigue prometiendo una operación segura. Crawlers, prefetchers, verificadores de enlaces y caches pueden emitir GET sin intención de causar un cambio.
Un método es seguro cuando su semántica definida es esencialmente de lectura: el cliente no solicita ni espera un cambio de estado en el servidor. GET, HEAD, OPTIONS y TRACE son seguros según RFC 9110. Eso no prohíbe todo efecto incidental. El servidor puede escribir logs, métricas o facturación publicitaria. La distinción es responsabilidad: esos efectos no forman parte de lo solicitado por el cliente.
Un método es idempotente cuando múltiples requests idénticos tienen el mismo efecto pretendido sobre el servidor que uno solo. Los métodos seguros, PUT y DELETE son idempotentes. La propiedad no exige respuestas idénticas. El primer DELETE /sessions/7 puede devolver 204; el segundo, 404. Si la sesión permanece eliminada, el efecto solicitado no se acumuló.
La cacheabilidad responde a otra pregunta: si una respuesta puede almacenarse y reutilizarse bajo reglas definidas. La atomicidad pregunta si un conjunto de cambios se observa como una unidad indivisible. La autorización pregunta si un principal puede realizar la acción sobre ese recurso en ese contexto. Ninguna se deduce de otra.
Desliza horizontalmente para consultar todas las columnas.
GET y HEAD
GET solicita transferir una representación seleccionada. HEAD solicita la misma semántica que GET sin contenido de respuesta. Ninguno debe ejecutar una acción insegura escogida por parámetros. «Pero sólo el panel interno conoce la URL» no repara el contrato: navegadores, scanners o herramientas pueden visitarla.
GET no significa automáticamente «barato». Una representación puede requerir una consulta costosa. El servidor debe imponer límites, paginación y controles de abuso sin alterar la expectativa de que observar no modifica el recurso. Tampoco significa «público»: una lectura segura puede requerir autorización estricta.
POST
POST pide al recurso que procese el contenido según su semántica. Puede crear un subordinado, iniciar una acción, enviar un comando o producir un cálculo. No es idempotente por definición. Repetir POST /transfers podría crear dos transferencias si el contrato no añade una forma de deduplicación.
Eso no vuelve a POST defectuoso. Significa que cliente y servidor necesitan un protocolo adicional cuando esperan retries. La propiedad pertenece a la operación concreta, no a una superstición sobre el método. Un POST puede ser seguro en un recurso particular o tolerante a retries por diseño, pero los intermediarios no deben asumirlo sin conocimiento explícito.
PUT
PUT solicita crear o reemplazar el estado del recurso de destino con el estado definido por la representación enviada. Es idempotente porque repetir el mismo reemplazo pretende dejar el mismo estado. No es un sinónimo universal de «actualización completa» para cualquier arquitectura; el servidor debe documentar qué propiedades controla la representación, cómo trata campos omitidos y qué validadores devuelve.
La idempotencia de PUT no evita actualizaciones perdidas. Dos clientes pueden leer v7, editar cambios distintos y enviar reemplazos idempotentes; el último sobrescribe al primero. La repetición individual no acumula efectos, pero la concurrencia entre intenciones diferentes sigue siendo conflictiva.
DELETE
DELETE solicita eliminar la asociación entre el recurso y su funcionalidad actual. Puede haber borrado lógico, retención legal o limpieza asíncrona. La semántica observable debe quedar clara. Ser idempotente no garantiza que todos los efectos internos terminen antes de responder ni que cada respuesta tenga el mismo status.
Una auditoría escrita por cada intento tampoco viola necesariamente idempotencia: RFC 9110 permite efectos secundarios no idempotentes que no fueron solicitados. Lo crítico es que el efecto de dominio solicitado —por ejemplo, revocar una clave— no se duplique de manera acumulativa.
PATCH
PATCH aplica instrucciones parciales al recurso. RFC 5789 lo define como no seguro y no idempotente por defecto. Todo depende del formato. «Reemplaza /name por Ada» puede ser idempotente; «incrementa /balance en 10» no lo es. Un patch basado en una versión equivocada puede corromper la intención aunque sea sintácticamente válido.
Cuando las instrucciones dependen de una base conocida, el cliente debe usar una request condicional, por ejemplo un ETag fuerte en If-Match. La precondición evita aplicar el patch sobre una representación distinta de la editada. La palabra PATCH no aporta esa protección por sí sola.
Autorización por objeto y operación
La autenticación establece una identidad conforme a un mecanismo. La autorización decide si esa identidad puede efectuar una acción sobre un recurso. Una API falla si comprueba el token y luego confía en cualquier ID enviado por el cliente. OWASP denomina Broken Object Level Authorization a la clase donde el consumidor puede manipular identificadores para alcanzar objetos ajenos.
Cada endpoint que recibe un identificador y actúa sobre un objeto necesita una decisión server-side. Debe usar el objeto resuelto, no sólo filtros de interfaz. Una forma útil de expresar el contexto es:
permitir(principal, acción, recurso, tenant, estado, relación, propósito)
No todos los sistemas usan todos esos ejes, pero omitirlos por accidente crea autoridad implícita. Un administrador de proyecto puede leer un reporte sin poder aprobarlo; un usuario puede editar su perfil sin cambiar el rol; un operador puede actuar sólo durante una guardia; una cuenta suspendida puede observarse pero no transferir.
Filtrar la colección y autorizar el detalle son ambos necesarios. Si GET /projects muestra sólo proyectos permitidos pero GET /projects/{id} busca directamente por clave global, el atacante no necesita que la lista revele el ID. Puede obtenerlo de logs, enlaces, errores o inferencia. Los identificadores no son secretos robustos.
Una respuesta 404 puede ocultar si el objeto existe y reducir enumeración; 403 puede ser apropiado cuando la existencia no es sensible. Esa elección no reemplaza la decisión. El servidor debe evitar diferencias laterales —tiempo, tamaño, detalles— cuando contradigan la política de ocultación.
Concurrencia: idempotencia no evita lost update
Supongamos que Ana y Bruno leen el mismo perfil con ETag "v7". Ana cambia el correo; Bruno cambia el idioma. Si ambos envían un PUT sin precondición, el último reemplazo puede borrar silenciosamente el cambio anterior. Cada PUT sigue siendo idempotente de forma aislada. El defecto es una decisión de concurrencia no expresada.
HTTP ofrece validadores. Un ETag identifica una versión seleccionada de una representación. If-Match hace condicional el método: el servidor sólo debe aplicarlo si una etiqueta actual coincide mediante comparación fuerte. Si el recurso ya cambió, la precondición falla y el servidor puede responder 412 Precondition Failed.
Vista adaptada. Toca el diagrama para ampliarlo.
La secuencia defendible es:
- ambos reciben la representación
v7y su ETag; - Ana envía el cambio con
If-Match: "v7"; - el servidor compara, aplica y produce
v8; - Bruno envía su intención con
If-Match: "v7"; - la comparación contra
v8falla antes del método; - Bruno relee, comprende la diferencia y reconcilia.
No debe resolverse automáticamente tomando el último documento si el dominio no define una fusión segura. Tampoco basta una fecha con resolución insuficiente para cambios rápidos. If-Match exige comparación fuerte porque el cliente intenta impedir cualquier cambio en los datos de representación relevantes.
RFC 9110 permite que un servidor responda éxito ante una precondición falsa si puede determinar que la misma operación ya se aplicó. Es una excepción útil para una respuesta previa perdida, pero exige evidencia suficiente. No autoriza a tratar cambios «parecidos» de usuarios distintos como equivalentes.
Status y errores forman parte del contrato
El status HTTP comunica semántica genérica a clientes, proxies y observabilidad. El contenido puede añadir detalles de dominio. Deben concordar.
201 Createdindica creación y normalmente identifica el recurso creado.202 Acceptedindica aceptación para procesamiento; no prueba terminación ni éxito final.204 No Contentindica éxito sin contenido de respuesta.400 Bad Requestcubre un problema del request que impide o desalienta procesarlo de nuevo sin cambios.401 Unauthorizedsolicita autenticación aplicable; su nombre histórico no significa «autenticado pero prohibido».403 Forbiddenindica que el servidor entiende el request pero rehúsa cumplirlo.404 Not Foundpuede significar ausencia o decisión de no revelar existencia.409 Conflictexpresa un conflicto con el estado actual del recurso.412 Precondition Failedexpresa que una precondición HTTP evaluó a falso.422 Unprocessable Contentindica contenido comprendido en sintaxis y tipo, pero cuyas instrucciones no pueden procesarse.
No hay una correspondencia universal entre cada regla de dominio y un status. La API debe decidir y documentar. Lo importante es no usar 200 para envolver todos los errores como {success:false}: eso priva a infraestructura y clientes de semántica común. Tampoco debe inventar un status por cada caso cuando un tipo de problema puede especializarlo.
RFC 9457 define Problem Details para errores HTTP, normalmente como application/problem+json. type identifica una clase estable de problema; title la resume; status repite de forma consultiva el status HTTP; detail explica la ocurrencia a humanos; instance identifica esa ocurrencia. Extensiones documentadas pueden transportar datos estructurados.
El cliente no debe parsear frases de detail para tomar decisiones. La localización o redacción puede cambiar. Debe usar type y campos estructurados. El servidor, a su vez, no debe filtrar stack traces, consultas, secretos o existencia sensible mediante el detalle. Un formato consistente no justifica una fuga consistente.
El problema real de los retries
En una red distribuida, «no recibí respuesta» no equivale a «el servidor no actuó». La conexión puede romperse antes del envío, durante el contenido, después de que el servidor confirme la transacción o mientras regresaba la respuesta. Desde el cliente, varios mundos son compatibles con el mismo timeout.
Los métodos idempotentes permiten repetir el request idéntico cuando la respuesta se pierde, porque el efecto pretendido no se acumula. Incluso entonces deben considerarse credenciales expiradas, precondiciones, límites de retry y cambios de contexto. Idempotente no significa «reintentar para siempre».
Para un POST no idempotente, crear una solicitud nueva después de un timeout puede duplicar el efecto. Consultar primero ayuda si existe un identificador estable. Otra opción es un contrato de clave de idempotencia. Ese contrato debe ser más preciso que «el cliente manda un UUID».
Una clave de idempotencia es un protocolo de estado
El borrador IETF draft-ietf-httpapi-idempotency-key-header-07 propone Idempotency-Key para hacer tolerantes a fallos operaciones no idempotentes. A fecha de revisión está expirado y no es un RFC. Conviene usar sus conceptos como diseño explícito, no asumir interoperabilidad normativa universal.
Una implementación robusta necesita responder siete preguntas.
1. Alcance
¿Dónde debe ser única la clave? Una key global facilita detección pero puede filtrar colisiones entre clientes. Es común vincularla al principal o tenant, operación y quizá recurso: (tenant, principal, operation, key). El scope debe impedir que un usuario observe o bloquee la solicitud de otro.
2. Huella
La misma key sólo puede representar la misma intención. El servidor calcula o conserva una huella de los componentes contractuales: método, destino normalizado, representación relevante y quizá versión. Si reaparece la key con otro importe o beneficiario, no debe devolver silenciosamente el resultado anterior ni ejecutar la variante. Debe rechazar el reuse como conflicto definido.
La huella exige canonicalización consciente. Hashear bytes JSON crudos hace distintos dos objetos equivalentes con espacios o orden de miembros; canonicalizar demasiado puede borrar diferencias significativas. El contrato decide qué campos forman la identidad de la operación.
3. Reserva atómica
El registro se crea antes del efecto mediante una operación atómica. Si dos requests concurrentes comprueban ausencia y ambos ejecutan antes de insertar, la clave no protegió nada. Un constraint único, compare-and-set, transacción o primitiva equivalente debe producir un único dueño.
4. Estado concurrente
El registro necesita al menos distinguir PENDING y COMMITTED; algunos diseños añaden un fallo definitivo reintentable o no reintentable. Si llega un duplicado igual mientras el primero está pendiente, puede esperar, recibir un estado «en progreso» o una respuesta definida. No debe ejecutar el efecto otra vez.
5. Resultado reproducible
Cuando la operación se confirma, el registro vincula el resultado suficiente para contestar al duplicado: status, ubicación, identificador y contenido o una referencia estable. Reproducir no significa necesariamente copiar cada header temporal. El contrato debe evitar devolver datos que el principal actual ya no pueda ver; la autorización sigue evaluándose donde corresponda.
6. Fallos y atomicidad
Registrar COMMITTED y producir el efecto deben compartir una frontera coherente. Si se cobra y luego falla el registro, un retry no sabe del cobro. Si se marca éxito antes del cobro y el proceso cae, los duplicados reciben un éxito falso. Una transacción local, outbox, reconciliación o diseño de dominio debe cerrar esa ventana. El mecanismo exacto depende de dónde vivan los efectos; el capítulo 59 abordará colas y eventos.
7. Retención
El servidor no puede recordar todas las claves para siempre. Debe publicar cuánto dura la protección y qué ocurre después. El cliente conserva la misma key durante esa ventana y no crea otra sólo porque su espera terminó. Cuando una operación financiera exige deduplicación más larga que una cache técnica, conviene además un identificador de negocio con unicidad durable.
Vista adaptada. Toca el diagrama para ampliarlo.
Caso trabajado: crear una transferencia
Una aplicación envía POST /transfers con origen, destino, moneda, importe e Idempotency-Key: "k-7". La sesión autentica a Alice en el tenant T1. El servidor no empieza por mover fondos.
Primero valida formato, límites y moneda. Después resuelve las cuentas y autoriza a Alice para crear esa transferencia desde la cuenta origen en T1. Comprobar que Alice puede ver la cuenta no basta: la acción es transfer, puede requerir límites, segundo factor o separación de funciones.
El servidor deriva el scope (T1, Alice, create-transfer, k-7) y una huella de la intención normalizada. Intenta reservar atómicamente. Si no existe, crea PENDING y obtiene el derecho exclusivo a ejecutar. Si existe con otra huella, responde un problema de conflicto. Si existe igual y está PENDING, no mueve fondos otra vez. Si está COMMITTED, devuelve el resultado registrado conforme al contrato.
El débito, crédito, identificador de transferencia y transición del registro deben formar una unidad consistente. En una sola base de datos podría ser una transacción con constraints de balance y unicidad. Entre servicios hará falta un protocolo más amplio; llamar «exactly once» a un conjunto de mensajes no lo vuelve atómico.
Supón que la transacción confirma tr_91, pero la respuesta se pierde. El cliente sólo sabe unknown. Repite la misma intención con la misma key. El servidor encuentra COMMITTED y devuelve la referencia a tr_91; no crea tr_92. Si el cliente cambia el importe pero reutiliza k-7, la huella detecta la contradicción y rechaza.
Si en cambio el cliente inventa k-8 tras el timeout, el servidor observa una solicitud nueva. No tiene base contractual para asociarla con k-7. Puede crear otra transferencia. La prevención no reside en la aleatoriedad del UUID, sino en mantener identidad de intención a través de la incertidumbre.
Contratos asíncronos y 202
Una operación larga puede responder 202 Accepted. El status significa que fue aceptada para procesamiento, no que terminó. Un diseño útil ofrece un recurso de operación, por ejemplo Location: /operations/op_31, con estado pending, succeeded o failed, resultado y problemas observables.
La aceptación debe tener semántica de idempotencia propia. Si el cliente repite, ¿recibe la misma operación o crea otra? Si la cola rechaza después de responder 202, ¿cómo se manifiesta? Si el worker termina pero el status no se actualiza, ¿qué reconcilia? Estas preguntas pertenecen a la frontera entre request síncrono y procesamiento asíncrono y se desarrollarán en el capítulo 59.
Por ahora basta una regla: no traduzcas «aceptado» como «completado» en UI, logs ni auditoría. La evidencia de recepción, ejecución y efecto final son eventos distintos.
Versionado y compatibilidad
Una API evoluciona en dos direcciones: cambia el servidor mientras existen clientes antiguos, y cambian los clientes mientras existen respuestas antiguas o caches. Añadir un campo suele ser compatible sólo si los consumidores ignoran extensiones desconocidas. Eliminarlo, cambiar su tipo o reinterpretar un valor puede romper aunque la ruta permanezca.
Los enums son especialmente delicados: un cliente que asume conjunto cerrado puede fallar ante un nuevo estado. Las fechas requieren formato, zona y precisión. Números monetarios no deben depender de float binario sin contrato. Los identificadores deben tratarse como opacos. Los límites de paginación, orden y consistencia también forman parte de la interfaz.
Versionar toda la API en la URL no resuelve semántica. Puede ser una estrategia de ruptura, pero cada versión necesita política de soporte, migración y retirada. La compatibilidad se prueba con productores y consumidores reales, no sólo validando el documento OpenAPI.
Método de revisión de una operación
Para revisar un endpoint, evita empezar por «¿usa el verbo REST correcto?». Reconstruye el contrato:
- Identidad del recurso. ¿Qué concepto lógico identifica la URI? ¿Es colección, miembro, vista, operación o proceso?
- Representación. ¿Qué significa cada campo, qué omite, cómo negocia versión y qué invariantes expresa?
- Semántica del método. ¿La operación respeta seguridad e idempotencia? ¿Qué efecto exacto solicita?
- Autoridad. ¿Qué principal realiza qué acción sobre qué objeto y tenant? ¿La decisión ocurre después de resolver el objeto?
- Precondiciones. ¿Qué versión o estado debe seguir vigente? ¿Cómo se evita lost update?
- Frontera de commit. ¿Qué cambios deben ser atómicos? ¿Qué observa el cliente si la respuesta se pierde?
- Retry. ¿Puede repetirse? ¿Con la misma clave? ¿Cuál es el scope, huella, estado concurrente y retención?
- Errores. ¿Status,
typey campos estructurados permiten corregir o adjudicar sin parsear frases? - Asincronía. Si responde 202, ¿cómo se observa la operación y cómo se reconcilia?
- Evidencia. ¿Hay pruebas de contrato, concurrencia y autorización negativa, no sólo ejemplos felices?
Este método convierte una ruta aparentemente pequeña en un conjunto verificable de promesas. También descubre dónde no existe todavía una decisión: «el framework lo hace» no explica scope de una key; «la base usa transacciones» no prueba que incluya el envío externo; «el schema valida» no autoriza el objeto.
Errores recurrentes
Recurso igual a fila. Acopla el contrato al almacenamiento y borra vistas, agregados y autoridad. Corrige separando identificación, representación y modelo interno.
Idempotente igual a misma respuesta. Confunde efecto con observación. Un DELETE puede producir 204 y luego 404 sin acumular borrados.
Idempotente igual a atómico. Un PUT puede ser idempotente y, aun así, perder actualizaciones o dejar cambios parciales si la implementación no cierra su transacción.
Autenticado igual a autorizado. Un token válido no concede todos los IDs. Prueba cambio de objeto, tenant, rol, relación y estado.
UUID igual a deduplicación. Una key sin scope, huella, reserva atómica, retención ni resultado es sólo una cadena. Dos requests concurrentes todavía pueden ejecutar dos veces.
Timeout igual a fallo. El cliente desconoce el resultado. Consultar o repetir bajo contrato conserva seguridad; crear una nueva operación puede duplicarla.
OpenAPI igual a cumplimiento. El documento declara una interfaz. Se necesitan pruebas runtime y observación de producción para demostrarla.
202 igual a éxito final. Sólo indica aceptación. El sistema debe exponer estado y eventual resultado.
Transferencia al capítulo 59
Este capítulo cerró el request síncrono en su frontera más difícil: el cliente puede perder la respuesta después del commit. La clave de idempotencia permite recuperar identidad de una intención, pero no explica por sí sola qué ocurre cuando el trabajo pasa a una cola, un evento se entrega varias veces o varios consumidores producen efectos.
El capítulo 59 estudiará colas, eventos y procesamiento asíncrono. Allí separaremos cinco pares: comando y evento; entrega y procesamiento; orden global y orden por clave; recepción y efecto confirmado; reentrega del mensaje y duplicación del efecto. La base permanece: definir recurso, autoridad, frontera de estado y evidencia antes de prometer garantías.
Síntesis
Una API HTTP es un contrato observable. La URI identifica un recurso; la representación comunica un estado; la persistencia sigue siendo interna. El método aporta semántica, pero seguridad, idempotencia, cacheabilidad, atomicidad y autorización son dimensiones diferentes.
GET no debe causar una acción solicitada insegura. PUT y DELETE son idempotentes por efecto pretendido, no por igualdad de respuestas. PATCH depende de su formato y puede necesitar If-Match. Los validadores y precondiciones evitan lost update cuando expresan la versión que el cliente realmente editó.
La autorización evalúa principal, acción, recurso y contexto en cada operación. Status y Problem Details permiten errores interoperables sin parsear prosa. Un timeout conserva un resultado desconocido. Para hacer retry-safe una operación no idempotente, la key necesita scope, huella, reserva atómica, estados concurrentes, resultado recuperable y retención. El identificador por sí solo no ofrece la garantía.
Fuentes primarias
- IETF, RFC 9110, HTTP Semantics, §§3, 8.8, 9, 13 y 15; RFC Editor, 2022.
- IETF, RFC 5789, PATCH Method for HTTP, §2; RFC Editor, 2010.
- IETF, RFC 9457, Problem Details for HTTP APIs, §§3–5; RFC Editor, 2023.
- OpenAPI Initiative, OpenAPI Specification 3.2.0; Specification, consultada 2026-10-06.
- OWASP, API Security Top 10 2023, API1: Broken Object Level Authorization; OWASP API Security, consultado 2026-10-06.
- IETF HTTPAPI, The Idempotency-Key HTTP Header Field,
draft-ietf-httpapi-idempotency-key-header-07; Datatracker, Internet-Draft expirado, consultado 2026-10-06.


