Forma RESTful de crear múltiples elementos en una solicitud

122

Estoy trabajando en un programa de servidor de cliente pequeño para recopilar pedidos. Quiero hacer esto de una manera "REST (ful)".

Lo que quiero hacer es:

Recoja todas las líneas de pedido (producto y cantidad) y envíe el pedido completo al servidor

Por el momento veo dos opciones para hacer esto:

  1. Envíe cada línea de pedido al servidor: POST qty y product_id

En realidad no quiero hacer esto porque quiero limitar el número de solicitudes al servidor, así que la opción 2:

  1. Recoja todas las líneas de pedido y envíelas al servidor de una vez.

¿Cómo debo implementar la opción 2? Un par de ideas que tengo es: Envuelva todas las líneas de pedido en un objeto JSON y envíe esto al servidor o use una matriz para publicar las líneas de pedido.

¿Es una buena idea o una buena práctica implementar la opción 2? De ser así, ¿cómo debo hacerlo?

¿Qué es una buena práctica?


fuente

Respuestas:

74

Creo que otra forma correcta de abordar esto sería crear otro recurso que represente su colección de recursos. Por ejemplo, imagine que tenemos un punto final como /api/sheep/{id}y podemos POSTAR /api/sheeppara crear un recurso ovino.

Ahora, si queremos admitir la creación masiva, deberíamos considerar un nuevo recurso de bandada en /api/flock(o /api/<your-resource>-collectionsi carece de un nombre más significativo). Recuerde que los recursos no necesitan asignarse a su base de datos o modelos de aplicación . Este es un error común.

Los recursos son una representación de nivel superior, sin relación con sus datos. Operar en un recurso puede tener efectos secundarios significativos, como disparar una alerta a un usuario, actualizar otros datos relacionados, iniciar un proceso de larga duración, etc. Por ejemplo, podríamos asignar un sistema de archivos o incluso el pscomando unix como API REST.

Creo que es seguro asumir que operar un recurso también puede significar crear varias otras entidades como efecto secundario.

miguelcobain
fuente
Estoy de acuerdo con esto. Debe resumir el concepto de una colección de su recurso y tratarlo como un recurso. Esto le dará una mayor flexibilidad en el futuro, así, cuando se quiere empezar a hacer operaciones en este etc
villy393
Este es el enfoque correcto. Esto no interrumpe la solicitud POST Collection. Desde entonces, se utiliza para publicar una sola entidad. Enviar una solicitud masiva con una "entidad masiva separada" es el enfoque correcto.
Clasificador
2
¡Me gustas el punto final de la API que nombra tanto con ovejas y rebaño! Con cierto grado de abstracción, casi tiene una referencia bíblica: "Tengo otras ovejas que no son de este redil; debo traerlas también, y escucharán Mi voz; y se convertirán en un solo rebaño con un solo pastor". Juan 10:16.
Evgeny
1
Curiosamente, la gente recomienda usar la forma plural (de la colección) en la URL cuando desee crear un solo recurso, de esta manera: envíe una POST a / api / books para crear un libro. Pero luego, cuando desea crear 100 libros (en una sola solicitud como json), ¿en qué URL publicaría la colección de 100 libros? ahí es donde comienza la inquietud.
code4kix
@ code4kix que podría usar /api/book-group, /api/book-collectiono algo similar.
miguelcobain
46

Aunque las operaciones masivas (p. Ej., Creación de lotes) son esenciales en muchos sistemas, el estilo de arquitectura RESTful no las aborda formalmente.

Descubrí que PUBLICAR una colección como sugirió básicamente funciona, pero surgen problemas cuando necesita informar fallas en respuesta a dicha solicitud. Tales problemas son peores cuando ocurren múltiples fallas por diferentes causas o cuando el servidor no admite transacciones. Mi sugerencia es que si no hay problemas de rendimiento, por ejemplo, cuando el proveedor de servicios está en la LAN (no WAN) o los datos son relativamente pequeños, vale la pena enviar 100 solicitudes POST al servidor. Que sea simple, comience con solicitudes separadas y si tiene un problema de rendimiento intente optimizar.

LiorH
fuente
3
¿Encontró usted mismo una solución para errores en caso de procesamiento por lotes? En una conexión móvil, enviar 100 solicitudes de publicación para mostrar una página parece una mala idea.
Thomas Ahle
Agrego los errores a una matriz, dirijo al usuario a una página de error de conflicto 419 (y devuelvo ese error al cliente), y visualizo la matriz de errores. Vea mi respuesta a continuación para más detalles.
Eric Fuller
55
Esto no tiene sentido. La pregunta es sobre el envío de un pedido de muchos artículos, que como muchos han dicho, puede hacerlo en la entidad de una solicitud POST. Cómo maneja el servidor eso es algo completamente diferente. En este caso, no veo ningún problema con la creación de un pedido, rellenando lo que pueda para ese pedido y también rellenando los detalles que no se pudieron llevar a cabo. De esa forma, un usuario puede ver su pedido y ver que todos menos N artículos se agregaron al pedido, pero que algunos estaban agotados o que el sistema no sabía qué hacer. Otra opción más simple pero menos fácil de usar es rechazar todo
thecoshman
2
@thecoshman muchos cambios en 3.25 años. Probablemente debería publicar una respuesta completamente formulada a la pregunta.
dlamblin
3
@dlamblin, sí, probablemente debería hacer muchas cosas ...
Tal
9

Facebook explica cómo hacer esto: https://developers.facebook.com/docs/graph-api/making-multiple-requests

Solicitudes por lotes simples

La API por lotes toma una matriz de solicitudes HTTP lógicas representadas como matrices JSON: cada solicitud tiene un método (correspondiente al método HTTP GET / PUT / POST / DELETE, etc.), un relative_url (la parte de la URL después de graph.facebook. com), matriz de encabezados opcionales (correspondientes a encabezados HTTP) y un cuerpo opcional (para solicitudes POST y PUT). Batch API devuelve una matriz de respuestas lógicas HTTP representadas como matrices JSON: cada respuesta tiene un código de estado, una matriz de encabezados opcional y un cuerpo opcional (que es una cadena codificada JSON).

rwitzel
fuente
1
Este es un enlace muy interesante, la solución propuesta me parece utilizable. De todos modos, en StackOverflow, la respuesta preferida es explicar el concepto de la solución en el cuerpo de una respuesta, ya que los enlaces pueden cambiar o desaparecer.
Jan Vlcinsky
77
Esa es realmente la forma en que Facebook lo hace, no necesariamente RESTful como el OP preguntó
0cd
Creo que una API de Batch (de Google, Facebook, etc. - @PuneetArora) es más útil cuando se agrupan varias solicitudes no relacionadas. Crear una solicitud que crea un elemento y luego agrupar todas esas solicitudes para enviar una colección de elementos es "locura" (Einstein). Simplemente cree una solicitud que pase una colección de artículos.
tfmontague
8

Tu idea me parece válida. La implementación es una cuestión de su preferencia. Puede usar JSON o solo parámetros para esto (matriz "order_lines []") y hacer

POST /orders

Dado que va a crear más recursos a la vez en una sola acción (orden y sus líneas) es vital validar cada uno de ellos y guardarlos solo si todos pasan la validación, es decir. deberías hacerlo en una transacción.

Milan Novota
fuente
6

Supongo que es mejor enviar solicitudes separadas dentro de una sola conexión . Por supuesto, su servidor web debería soportarlo

zakovyrya
fuente
5

De hecho, he estado luchando con esto últimamente, y esto es en lo que estoy trabajando.

Si una POST que agrega múltiples recursos tiene éxito, devuelve un 200 OK (estaba considerando un 201, pero el usuario finalmente no aterriza en un recurso que fue creado) junto con una página que muestra todos los recursos que se agregaron, ya sea en lectura -solo moda o editable. Por ejemplo, un usuario puede seleccionar y PUBLICAR múltiples imágenes en una galería utilizando un formulario que comprende solo una entrada de archivo único. Si la solicitud POST tiene éxito en su totalidad, se le presenta al usuario un conjunto de formularios para cada representación de recurso de imagen creada que le permite especificar más detalles sobre cada uno (nombre, descripción, etc.).

En el caso de que uno o más recursos no se puedan crear, el controlador POST cancela todo el procesamiento y agrega cada mensaje de error individual a una matriz. Luego, se devuelve un Conflicto 419 y el usuario se enruta a una página de error Conflicto 419 que presenta el contenido de la matriz de errores, así como un camino de regreso al formulario que se envió.

Eric Fuller
fuente
-2

No querrá enviar los encabezados HTTP para 100 líneas de pedido. Tampoco desea generar más solicitudes de las necesarias.

Envíe todo el pedido en un objeto JSON al servidor, a: servidor / pedido o servidor / pedido / nuevo. Devuelve algo que apunta a: server / order / order_id

También considere usar CREATE PUT en lugar de POST

Alegre
fuente
Supongo que mencionó el método HTTP POST. No existe el método CREATE HTTP.
Milan Novota el
No hay Oh espera, no había. Había PUT en su lugar.
Alegre el
22
¿Por qué demonios usarías PUT para crear contenido? Para esto es exactamente el método HTTP POST.
thecoshman
8
Utiliza PUT para crear recursos cuando desea que el cliente especifique el URI del recurso, como en webdav. No estoy de acuerdo con el uso del póster de PUT, pero tiene un lugar en la creación de recursos, aunque ese lugar puede tener un alcance limitado.
user602525
2
Nota: PUBLICAR una entidad debe hacer que la entidad se convierta en subordinada del recurso abordado en la solicitud y no sea idempotente. PUT reemplaza a la entidad en la dirección y es idempotente. La idempotencia (¿palabra?) Es una expectativa importante para los consumidores.
Luke Puplett el