Reputation: 10289
For a standard REST PUT request of to update single entity, for example, a document, using an endpoint that looks something like this:
[Route("documents/{id}")]
public void Put(int id, [FromBody]Document document)
there is a well-defined way to use HTTP status codes to communicate with the client, using an HTTP 200 status for a successful update, an HTTP 404 if document with the specified Id was not found, an HTTP 500 if there was a problem updating the record, etc.
My issue is that we have a RESTful API with potentially extremely high usage. For performance reasons, we would like to create a endpoint that will accept multiple document entities to update in a single PUT operation:
[Route("documents")]
public void Put([FromBody]IEnumerable<Document> documents)
with input such as this:
[
{"Id":1,"Name":"doc one","Author":"Fred"},
{"Id":2,"Name":"doc two","Author":"John"},
{"Id":3,"Name":"doc three","Author":"Mary"}
]
If a user submits 10 documents, and I am able only able to successfully update 9 of them, with remaining one failing due to some issue, I would like to commit the 9 successfully updated documents and then communicate to the user which updates succeeded and which ones failed.
One approach I could take is that if any of the submitted documents successfully update, return an HTTP 200. In the response object that I return to the client, I can include a list of those documents that succeeded and a list of documents that failed. For each of those that failed, I can include the reason why, along with maybe an HTTP status code for each failed document.
But should I be returning an HTTP 200 if some of the requests failed? This approach counts on the client to inspect the list of failed documents to see if there are problems. My fear is that the user will see the HTTP 200 and assume everything is fine.
The other option is that if the client submits 10 documents, and I am able to successfully update 9 of them and one fails, return the HTTP status code for the one that failed. For example, if one failed because the specified Id could not be found, return an HTTP 404, if it failed because the DB was unavailable, return an HTTP 500, etc.
This approach also has problems. For example, if two documents fail for different reasons, which HTTP status code should be returned? And does it make sense to return, for example, an HTTP 500 status for a request that successfully updated some of the items?
Do the REST guidelines give any suggestions for this issue of batch updates? Are there any recommended approaches for this issue?
Upvotes: 1
Views: 1646
Reputation: 5271
HTTP Status 207 Multi Status
can be used to handle batch processing.
When processing more than one entities, your API can return a 207
status response containing a list of responses:
Id
could be used as key.The RFC stated that the message is in XML but you can use JSON with your own structure. You can take a look at Jive API which handle batch processing to see an example.
Given the input
[
{"Id":1,"Name":"doc one","Author":"Fred"},
{"Id":2,"Name":"doc two","Author":"John"},
{"Id":3,"Name":"doc three","Author":"Mary"}
]
A full success would return a 207
http status, the response containing three 200
http statuses:
[
{
"Id": 1,
"status": 200,
"data" : { data returned for a single processing }
},
{
"Id": 2,
"status": 200,
"data" : { data returned for a single processing }
},
{
"Id": 3,
"status": 200,
"data" : { data returned for a single processing }
}
]
If there's a problem with entity with id 3 like missing author:
[
{"Id":1,"Name":"doc one","Author":"Fred"},
{"Id":2,"Name":"doc two","Author":"John"},
{"Id":3,"Name":"doc three"}
]
The response will still be a 207
but will contain two 200
http statuses for id 1 and 2 and a 400
status for id 3.
[
{
"Id": 1,
"status": 200,
"data" : { data returned for a single processing }
},
{
"Id": 2,
"status": 200,
"data" : { data returned for a single processing }
},
{
"Id": 3,
"status": 400,
"data" : { data returned for a single processing 400 error }
}
]
Upvotes: 2