Create single and multiple resources using restful

2019-03-24 16:05发布

问题:

In my API server I have this route defined:

POST /categories

To create one category you do:

POST /categories {"name": "Books"}

I thought that if you want to create multiple categories, then you could do:

POST /categories [{"name": "Books"}, {"name": "Games"}]

I just wanna confirm that this is a good practice for Restful HTTP API.

Or should one have a

POST /bulk

for allowing them to do whatever operations at once (Creating, Reading, Updating and Deleting)?

回答1:

In true REST, you should probably POST this in multiple separate calls. The reason is that each one will result in a new representation. How would you expect to get that back otherwise.

Each post should return the resultant resource location:

POST -> New Resource Location
POST -> New Resource Location
...

However, if you need a bulk, then create a bulk. Be dogmatic where possible, but if not, pragmatism gets the job done. If you get too hung up on dogmatism, then you never get anything done.

Here is a similar question

Here is one that suggests HTTP Pipelining to make this more efficient



回答2:

There's nothing particularly wrong with having a bulk operation that you POST to, to activate (it'll be non-idempotent so POST is the right verb) but there are some caveats:

  • You're making multiple resources, so you need to respond with multiple URLs. This means you can't use the redirect pattern: you'll have to send a list of URLs back in some form.

  • You have a problem in that bulk operations are often not very discoverable. Discoverability is one of the most important things about RESTfulness, as it means that someone can come along and figure out how to write a client without lots of help from the server author.

  • Dealing with partial failures when you've got bulk operations remains problematic. It's a problem with any other paradigm too (I've watched people tie themselves in knots over this when working with extensions to SOAP) so it isn't a surprise, but unless you can guarantee that all the creations will work, you're going to have to work out what happens when you make one resource and fail to make the second. (Also, if the bulk request wanted a third one done, would you go on and try that?)

The simplest approach is just to support one create per request; that's a much easier pattern to get right and is better understood all round.



回答3:

There's nothing wrong with creating multiple resources at once with POST (just don't try it with PUT). It's not "un-REST-ful", especially if you create a representation for the bulk operation itself. I suggest you create an index resource at the same time you create the individual resources, and return a "303 See Other" to it. That index representation would then contain links to all of the created resources (and possibly error information if any of them failed).

POST /categories/uploads/
[{"name": "Books"}, {"name": "Games"}]

    303 See Other
    Location: /categories/uploads/321/

(actually, now that I think about it, 201 might be better than 303)

GET /categories/uploads/321/

    200 OK
    Content-Type: application/json

    [{"name": "Books", "link": "/categories/Books/"},
     {"name": "Games", "error": "The 'Games' category already exists."}]


回答4:

In your case I would also go the /bulk resource way. But the pattern I would suggest is the following and from my understanding the most natural: Work with the 202 Accepted status code.

The idea of a bulk request is that the server should not be forced to answer immediately as this would mean client needs to wait until it's bulk request completed.

Here is the pattern:

POST /bulk [{"name": "Books"}, {"name": "Games"}]
202 Accepted | Location: /bulk/processing/status/resourceId

GET /bulk/processing/status/resourceId
entry = "REST in peace" | completed | 0 errors | /categories/category/resourceId
entry = "Walking dead" | processing | 0 errors ->

So, the client POSTs the bulk information to the server. The server just accepts them with a 202 which gives no guarantee about the processing state at the time of response. But the server also provides the link to a status resource. Here the client can have a look on each of the created resources and the processing state. When finished the client can access the resource via the given link. Error cases can be identified by the client and erroneous data might be resend by a PUT on the completed resource.

Finally, a good advice I am usually following is: Whenever you hit a resource in your design that cannot be mapped on a HTTP feature it is probably because of a missing resource.