http - explained - rest post example
Consecuencias de que POST no sea idempotente(API RESTful) (6)
¿Pero ahora tienes dos solicitudes que se pueden perder? Y el POST aún puede repetirse, creando otra instancia de recurso. No pienses demasiado en cosas. Simplemente haga que el proceso por lotes busque engaños. Posiblemente tenga algunas estadísticas de recuento de "acceso" sobre sus recursos para ver cuál de los candidatos engañados fue el resultado de una publicación abandonada.
Otro enfoque: controla los POST entrantes contra algún registro para ver si se repite. Debería ser fácil de encontrar: si el contenido del cuerpo de una solicitud es el mismo que el de una solicitud hace solo x tiempo, considérelo como una repetición. Y podría verificar parámetros adicionales como la IP de origen, la misma autenticación, ...
Me pregunto si mi enfoque actual tiene sentido o si hay una mejor manera de hacerlo.
Tengo varias situaciones en las que quiero crear nuevos objetos y dejar que el servidor asigne una ID a esos objetos. Enviar una solicitud POST parece ser la forma más adecuada de hacerlo. Sin embargo, dado que POST no es idempotente, la solicitud puede perderse y enviarla de nuevo puede crear un segundo objeto. También es posible que se pierdan solicitudes, ya que a menudo se accede a la API a través de redes móviles.
Como resultado, decidí dividir todo en un proceso de dos pasos. Primero enviando una solicitud POST para crear un nuevo objeto que devuelve el URI del nuevo objeto en el encabezado de la ubicación. En segundo lugar, realizar una petición PUT idempotente a la ubicación proporcionada para rellenar el nuevo objeto con datos. Si un nuevo objeto no se rellena dentro de las 24 horas, el servidor puede eliminarlo mediante algún tipo de trabajo por lotes.
¿Eso suena razonable o hay un mejor enfoque?
Gracias
Creo que también podría colapsar la creación y actualizar la solicitud en una sola solicitud (upsert). Para crear un nuevo recurso, el cliente POST un recurso "de fábrica", ubicado, por ejemplo, en / factory-url-name. Y luego el servidor devuelve el URI para el nuevo recurso.
Independientemente del método HTTP que utilice, teóricamente es imposible realizar una solicitud idempotente sin generar el identificador único del lado del cliente, temporalmente (como parte de algún sistema de comprobación de solicitudes) o como el ID permanente del servidor. Una solicitud HTTP que se pierde no creará un duplicado, aunque existe la preocupación de que la solicitud pueda tener éxito al llegar al servidor, pero la respuesta no llega al cliente.
Si el cliente final puede eliminar fácilmente duplicados y no causa conflictos de datos inherentes, probablemente no sea lo suficientemente grande como para desarrollar un sistema de prevención de duplicación ad-hoc. Use POST para la solicitud y envíe al cliente un estado 201 en el encabezado HTTP y el ID único generado por el servidor en el cuerpo de la respuesta. Si tiene datos que muestran que las duplicaciones son una ocurrencia frecuente o que cualquier duplicado causa problemas importantes, usaría PUT y crearía el ID único del lado del cliente. Use el ID creado por el cliente como ID de la base de datos; no hay ninguna ventaja en crear un ID único adicional en el servidor.
La única ventaja de la creación de POST sobre la creación de PUT es la generación de ID de servidor. No creo que valga la pena la falta de idempotencia (y luego la necesidad de eliminar duplicados u objetos vacíos).
En cambio, usaría un PUT con un UUID en la URL. Debido a los generadores UUID, está casi seguro de que la ID que genere del lado del cliente será única en el servidor.
Su método para generar identificadores en el servidor, en la aplicación, en una solicitud-respuesta dedicada, es muy bueno. La singularidad es muy importante, pero los clientes, como los pretendientes, seguirán repitiendo la solicitud hasta que tengan éxito, o hasta que obtengan una falla que estén dispuestos a aceptar (poco probable). Entonces necesitas obtener unicidad de algún lado, y solo tienes dos opciones. O el cliente, con un GUID como sugiere Aurélien, o el servidor, como usted sugiere. Me gusta la opción del servidor. Las columnas semilla en DB relacionales son una fuente de singularidad fácilmente disponible con cero riesgo de colisiones. Alrededor de 2000, leí un artículo que abogaba por esta solución llamada algo así como "Mensajes simples y confiables con HTTP", por lo que este es un enfoque establecido para un problema real.
Leyendo cosas de REST, se te puede perdonar por pensar que un grupo de adolescentes acaba de heredar la mansión de Elvis. Con entusiasmo, están discutiendo cómo reorganizar los muebles, y están histéricos ante la idea de que necesiten traer algo de casa. Se recomienda el uso de POST porque está ahí , sin abordar los problemas con solicitudes no idempotentes.
En la práctica, es probable que desee asegurarse de que todas las solicitudes inseguras a su API sean idempotentes , con la necesaria excepción de las solicitudes de generación de identidad, que, como usted señala, no importan. Generar identidades es barato y las que no se usan se descartan fácilmente. Como un guiño a REST, recuerda obtener tu nueva identidad con un POST, para que no se guarde en la memoria caché y se repita por todos lados.
En cuanto al debate estéril sobre lo que significa idempotente , digo que tiene que ser todo. Las solicitudes sucesivas no deberían generar efectos adicionales y deberían recibir la misma respuesta que la primera solicitud procesada. Para implementar esto, querrá almacenar todas las respuestas del servidor para que puedan ser reproducidas, y sus identificadores identificarán las acciones, no solo los recursos. Te echarán de la mansión de Elvis, pero tendrás una API a prueba de bombas.
bueno, todo depende, para empezar debes hablar más sobre los URI, los recursos y las representaciones y no preocuparte por los objetos.
El método POST está diseñado para solicitudes no ideopotentes, o solicitudes con efectos secundarios, pero se puede usar para solicitudes idempotentes .
en POST de datos de formulario a / some_collection /
normalize the natural key of your data (Eg. "lowercase" the Title field for a blog post)
calculate a suitable hash value (Eg. simplest case is your normalized field value)
lookup resource by hash value
if none then
generate a server identity, create resource
Respond => "201 Created", "Location": "/some_collection/<new_id>"
if found but no updates should be carried out due to app logic
Respond => 302 Found/Moved Temporarily or 303 See Other
(client will need to GET that resource which might include fields required for updates, like version_numbers)
if found but updates may occur
Respond => 307 Moved Temporarily, Location: /some_collection/<id>
(like a 302, but the client should use original http method and might do automatically)
Una función hash adecuada podría ser tan simple como algunos campos concatenados, o para campos grandes o valores se podría usar una función md5 truncada. Ver [función hash] para más detalles 2 .
Te he asumido:
- necesita un valor de identidad diferente que un valor hash
- los campos de datos utilizados para la identidad no se pueden cambiar