Header Ads Widget

Ticker

6/recent/ticker-posts

Comprensión de la idempotencia y la seguridad en el diseño de API

 


¿Qué significa en programación ser idempotente ? Hoy, veremos los conceptos de idempotencia y seguridad, e identificaremos qué los hace tan importantes en el contexto del diseño de API web.

Compararemos la idempotencia y la seguridad para ver en qué se diferencian y descubrir por qué esta división es importante. Aprenderemos qué métodos HTTP son idempotentes versus seguros , y descubriremos cómo aplicar este conocimiento en última instancia para crear API web seguras y predecibles.

¿Qué es la idempotencia, de todos modos?

En pocas palabras, una operación es idempotente si produce el mismo resultado cuando se llama una y otra vez. Una solicitud idéntica debería devolver un resultado idéntico cuando se realiza dos veces, dos mil o dos millones de veces. Sin embargo, la fuente de la mayor confusión en torno a este concepto proviene de la idea de resultados idénticos. Lo que esperamos ver son resultados idénticos en el formulario de devolución en lugar de en el valor de devolución .

Cuando se emite una llamada, la respuesta se puede dividir generalmente en dos campos diferentes: el formulario de devolución y el valor de devolución . Si tuviéramos que realizar una solicitud GET para una actualización del estado de un recurso, por ejemplo, podríamos obtener resultados muy diferentes según el recurso que se está inspeccionando y el momento en que hacemos la inspección.

Independientemente de ese cambio, que es simplemente un cambio de valor, esperaríamos que el formato de ese resultado (es decir, el tipo de paquete, la forma en que se muestran los datos, el método en el que se cifran, etc.) sea ​​exactamente el mismo . Si bien el resultado esperado debería ser idéntico, el valor de ese resultado puede cambiar. Aún puede realizar llamadas idempotentes a recursos que cambian, siempre que el recurso se devuelva en una estructura conocida, con todos los puntos finales conocidos respondiendo correctamente.

Una buena forma de enmarcar su comprensión de este concepto es pensar en cada llamada funcional como hacer una pregunta en otro idioma. Cuando le preguntas a alguien qué hora es en español - "¿que hora es?" - la respuesta a esa pregunta puede cambiar según la hora del día. Este sería un valor cambiante.

Sin embargo, la forma en la que espera la respuesta no cambia: solo porque son las 4 de la tarde, la persona que responde no va a empezar a usar "limones" como medida de horas, ni a responderle en francés. Cada respuesta estará estructurada en la forma, sintaxis y gramática que esperas, y no importa cuántas veces lo preguntes, siempre estará en español. Esta es la función de la llamada. Uno puede imaginar el caos que podría sobrevenir si una persona cambia constantemente entre español, francés, alemán e inglés dependiendo de la hora del día y de lo que se le pregunta; en esta situación, sería imposible formarse expectativas efectivas y coherentes.

Lo mismo ocurre en el espacio API. La llamada funcional no debe ser diferente con cada solicitud, sino que debe regresar de una manera conocida y esperada, independientemente de cuán diferente pueda ser el valor de respuesta. La idempotencia y la seguridad, que es un término relacionado también llamado “nulipotencia”, son esencialmente garantías de expectativas, asegurando a los clientes que sus llamadas podrán esperar, analizar y comprender las respuestas de una manera conocida.

Idempotencia y seguridad

Deberíamos tomarnos un momento para abordar la seguridad, ya que estos términos a menudo se usan indistintamente. Si bien definitivamente están relacionados, difieren algo significativamente, por lo que su uso coloquial como sinónimos es un problema por resolver. En los términos más simples, se dice que un método HTTP es "seguro" cuando no altera el estado del servidor; en otras palabras, un método "seguro" es aquel que funciona en modo de "sólo lectura".

Los métodos seguros pueden ser cambiados por el propio servidor, por supuesto, pero en esos casos, no es la solicitud la que realiza el cambio, sino el servidor que interactúa con la solicitud. Por ejemplo, los registros pueden actualizar y cambiar recursos en el servidor, pero el acceso a esos recursos no está causando el cambio y siempre (al menos si están programados correctamente) será "seguro".

La razón por la que estos términos a menudo se confunden es porque caen en una definición cruzada entre sí; esto es básicamente una situación de “cuadrado es un rectángulo, pero un rectángulo no es un cuadrado”. Dado que un método seguro siempre dará como resultado la misma forma (si no el mismo valor), incluso si los recursos cambian, son por definición idempotentes, pero algo puede ser idempotente y aún cambiar un recurso o estado del servidor, lo que significa que lo que es idempotente no es necesariamente seguro.

En consecuencia, la siguiente tabla muestra algunas verborrea HTTP común, y si es idempotente y seguro.

¿Por qué no hacer todo idempotente?

Entonces, debe hacerse la pregunta: si ser idempotente da como resultado la misma forma día tras día, ¿por qué no podemos simplemente hacer que todo sea idempotente? El problema es que a veces, en algunos casos especiales importantes, es deseable que tanto el valor como la forma cambien.

Por ejemplo, POST es por definición algo que da como resultado un cambio de estado del servidor y un cambio en la forma y el valor esperados. Si POST fuera idempotente, todo lo enviado y aceptado el servidor web ya tendría que existir en el servidor de alguna forma para responder con los mismos códigos y valor de respuesta. Por esa razón, POST no puede ser idempotente ni seguro: desafía el propósito mismo de la verborrea. El método en sí depende tanto de los recursos cambiantes como de las respuestas cambiantes después de cada solicitud.

Puede parecer que hay una excepción a esta regla con DELETE, pero tras una inspección más detallada, podemos ver que realmente es idempotente. Si bien DELETE elimina algo del servidor, eso es simplemente el cambio en el valor, ya sea que el elemento exista o no.

Sin embargo, la respuesta es la misma: un código de error que dice que el elemento existe o no, y si se eliminó o no. Independientemente de la función que se realice con DELETE, debería dar como resultado la misma respuesta, incluso si el valor en sí es diferente. Por lo tanto, podemos ver que incluso algo que parece no ser idempotente puede, en sí mismo, ser idempotente, solidificando la importancia de comprender verdaderamente esta definición conceptual.

Caveat Emptor

Por supuesto, todo esto viene con una gran advertencia: lo teórico no siempre es lo práctico. Si algo es idempotente, puede que no lo sea una vez que el desarrollador lo invoca. Una operación idempotente llamada de una manera no idempotente puede resultar en muchos problemas y es fundamentalmente una operación no idempotente. Esto es, en esencia, un mal diseño y debe evitarse en todo momento.

Un ejemplo de esa idempotencia mal interpretada se puede ver en este hilo de Twitter . En esta situación, se diseñó una API para alternar un interruptor de relé, que a su vez operaría los botones de una puerta de garaje. Sin embargo, el punto final fue programado para responder a las solicitudes GET. Se supone que GET es idempotente y seguro, pero debido a que GET se usaba de esta manera para activar la función en lugar de algo como POST, surgió un problema con la forma en que Apple sincroniza el contenido en múltiples dispositivos.

Dado que la pestaña que contenía la función GET estaba sincronizada, cada vez que se abría una nueva pestaña, este proceso de sincronización activaba la página, que automáticamente lanzaba la función GET. Esto, por supuesto, resultó en que la puerta se abriera cada vez que se creaba una pestaña. Durante varias noches, el usuario no sabía por qué la puerta de su garaje se abría en medio de la noche, y solo descubrió el problema después de analizar la forma en que la API manejaba las solicitudes.

En este caso, una configuración adecuada idempotente y segura habría negado este problema. Utilizar GET para alterar el estado del servo de la puerta del garaje es fundamentalmente incorrecto; esto es algo para lo que debería haberse utilizado PUT, mientras que GET solo debería haberse utilizado para leer el estado actual del servo de la puerta.

Si bien este es un ejemplo divertido, hay preocupaciones más serias en juego. Supongamos que hemos creado una aplicación de comercio que permite a los usuarios realizar el pago de una factura u otra transferencia monetaria. En un entorno idempotente y seguro, el usuario hará clic en el botón enviar una vez, generando automáticamente una función POST para actualizar el estado del pedido. Después de esto, se usará una llamada GET cuando el usuario haga clic más veces, simplemente devolviendo el estado del pedido o una advertencia de que el pedido ya se está procesando.

Sin embargo, si no implementamos esta configuración, cada clic de ese botón, en teoría, agregará un pedido adicional al backend. Si un usuario hace clic en ese botón 100 veces y todas las 100 veces no son idempotentes ni seguras, eso significa que se generarán 100 pedidos separados del mismo cliente.

Si bien esto es mucho más un problema de diseño que de simple idempotencia, podemos comenzar a ver cuán importante es esta herramienta en el conjunto de herramientas API, si se usa correctamente. No implementarlo correctamente puede ser costoso, peligroso y, en última instancia, provocar que su base de código se vea directamente socavada por una implementación deficiente.

Contratos, estandarización y confianza

Un valor importante aquí es la idea de tener contratos preexistentes con su base de usuarios y fomentar una comprensión de cómo funciona el sistema. Los clientes deben poder confiar en las API con las que interactúan y, a la inversa, las API deben estar lo suficientemente estandarizadas para admitir esto. No utilizar enfoques idempotentes y seguros es básicamente similar a pedirle a sus clientes que no solo confíen en usted ciegamente, sino que también sean psíquicos: que conozcan las limitaciones del sistema, que sepan qué es seguro y qué no, y que esperen que el cliente lo sepa. la forma de la respuesta cada vez que cambia.

Ese es claramente un precedente peligroso de establecer y que complica la relación entre el usuario y el cliente de una manera bastante significativa. La carga de la comunicación contratada recae en el desarrollador, no en el cliente; no comprender esto es un problema importante.

Conclusión

En términos inequívocos, no funcionar de manera idempotente y segura es peligroso y, en última instancia, es usar las cosas de una manera para la que no están diseñadas. Las opciones de verborrea HTTP están diseñadas para hacer cosas muy específicas, por lo que obligarlos a hacer otras cosas, a veces con propósitos contrarios, es muy peligroso y, en última instancia, inútil. GET no está destinado a hacer lo que hace POST, es por eso que ambos existen.

Establecer la comprensión adecuada y hacer cumplir el diseño adecuado mejora la experiencia del usuario y, en última instancia, mejora la solidez y la usabilidad de su sistema. No adoptar estos conceptos simples y la ética del diseño es una receta para la confusión en el mejor de los casos y el fracaso en el peor.



Publicar un comentario

0 Comentarios