2011-06-13 21 views
10

Tengo una pregunta sobre el diseño de API REST. Aquí es un simple (tal vez demasiado simple) de la API:REST API con varios comandos por recurso

GET /ecommerce/order/123 

POST /ecommerce/order (create a new order) 

PUT /ecommerce/order/123 (update an existing order) 

DELETE /ecommerce/order/123 (cancel order) 

Pero lo que si quería el cliente que introduzca una razón para un fin de ser cancelada? Necesitaría enviar datos de publicaciones a la API, pero eso no funcionará con DELETE. Para atender esto, tendría que cambiar DELETE a PUT. Luego publicaría dos recursos diferentes para actualizar y cancelar.

Otra solución sería cambiar la API:

GET /ecommerce/order/123 

POST /ecommerce/order/create (create a new order) 

PUT /ecommerce/order/update/123 (update an existing order) 

DELETE /ecommerce/order/cancel/123 (cancel order) 

No estoy seguro de que es la mejor opción.

Hay una pregunta más general sobre cómo REST API maneja varios comandos para un solo recurso.

¡Cualquier entrada sería apreciada! Voy a leer REST en la práctica muy pronto, pero esta pregunta me resulta incómoda.

Respuesta

6

Una opción podría ser crear un nuevo recurso. CancelledOrder, quizás.

A continuación, podría POST un nuevo CancelledOrder:

POST /ecommerce/cancelledOrder 
Entity: 
    order: /ecommerce/order/123 
    reason: "Problem with order" 

Se podría también/en lugar PUT un CancelledOrder:

PUT /ecommerce/cancelledOrder/123 
Entity: 
    reason "Problem with order" 

continuación, la aplicación podría borrar la orden de 123 o actualizar su estado a "Cancelado" , o haga lo que sea que requieran las reglas de su negocio. Para colmo, podría no admitir el método DELETE directamente para /ecommerce/order/N, devolviendo un 405 Method Not Allowed.

La solución PUT puede usar idempotence para su ventaja; PUT ting el CancelledOrder varias veces siempre resultaría en la cancelación del pedido.

Cabe señalar que es probable que sus sugerencias para cambiar la API (por ejemplo, /ecommerce/order/create) no sean RESTful, ya que está definiendo métodos en los identificadores de recursos.

+0

Me gusta esta respuesta. Los recursos y las entidades de dominio no son uno a uno. –

+1

No me gusta realmente el nombre de CancelledOrder, un nombre de recurso mejor sería OrderCancellation o, en otras palabras, exponer una acción como recurso. Esto también es bastante bueno en el caso de acciones reversibles, ya que podría usar eliminar en la "acción". – Maxem

+0

También cuando esto no se ajusta, me gusta lo que este comentario menciona para el mismo problema: http://programmers.stackexchange.com/a/270421/211215 – Almund

2

(La pregunta es bastante viejo, pero yo sólo pensé en mejorarlo, ya que no me gusta ninguna solución por ahí.)

La solución es simple. Pon una razón en el cuerpo de la solicitud.

DELETE /ecommerce/order/123 
Content-Type: text/plain 
Content-Length: 48 

Order was cancelled due to a customer's request. 

La semántica del cuerpo depende de usted para decidir. Si solo quieres un texto claro, usaría text/plain como se muestra arriba. Si se requieren metadatos más complicados, complicaría las cosas aún más.

En mi opinión, esto es mucho mejor que Javaesque RPC-like OrderCancellator.execute(order) (porque POST es el nombre de HTTP para "ejecutar").

Tenga en cuenta que, mientras que las especificaciones no dicen nada al respecto, algunos servidores may discard DELETE request's body.A draft on HTTP/1.1 message semantics aclara:

Los cuerpos en las solicitudes DELETE no tienen una semántica definida. Tenga en cuenta que enviando un cuerpo en una solicitud DELETE puede causar que algunas implementaciones existentes rechacen la solicitud.

Otra opción es emitir un encabezado:

DELETE /ecommerce/order/123 
X-Reason: Cancelled due to an UFO invasion. 

Cada vez para elegir encabezados o cuerpo de la entidad depende del tamaño y formato de los datos. Algunos datos se ajustan bien a los encabezados HTTP, otros no. Ciertamente, se puede pasar una identificación numérica de ticket, es incierto sobre cadenas (piense en Unicode) y es seguro que nadie en su sano juicio quiere pasar allí un JPEG Base64.

+0

Para mí, el motivo de la cancelación parece información que pertenece a un recurso de algún tipo. Los encabezados (según entiendo) deberían ser metainformación sobre la solicitud en sí, en lugar de tener datos comerciales reales. La sugerencia de cuerpo/entidad 'DELETE' tiene potencial, pero los enlaces que has proporcionado sí plantean algunas inquietudes. –

+0

AFAIK no hay nada que diga que DELETE no puede tener efectos secundarios, por lo que no tiene que crear explícitamente un recurso de cancelación usando una semántica POST ambigua (que eliminaría el orden junto con la creación del registro de cancelación). De la misma manera, GET se considera idempotente, pero escribir un registro en el archivo de registro de acceso o [aumentar un contador de visitas] (http://www.intertwingly.net/blog/784.html) no lo infringe. PUT (reemplazar) una orden con una versión actualizada marcada como cancelada me parece bien, sin embargo. – drdaeman

+0

Puntos verdaderos. De hecho, miré mi respuesta hoy y me encontré teniendo reservas al respecto. Todavía funciona, pero hay formas mejores y más impulsadas por hipertexto para lograr esto. Estaba trabajando en otra respuesta, pero me distraí. –

4

Sé que esto es una respuesta muy tarde, pero mejor utilizar la primera serie de comandos, pero cambiar el comando para cancelar a:

de POST/tienda/pedido/123/cancelar

Qué es una forma genérica de manejar varias operaciones en un recurso existente. No veo por qué una cancelación de pedido llevaría a la eliminación del pedido en sí, al menos no al instante. Los usuarios probablemente aún quieran ver el pedido en el sistema. El orden es también donde almacenaría el motivo de la cancelación.