HTTP 202 Accepted (HTTP/1.1)
You are looking for HTTP 202 Accepted
status. See RFC 2616:
The request has been accepted for processing, but the processing has not been completed.
HTTP 102 Processing (WebDAV)
RFC 2518 suggests using HTTP 102 Processing
:
The 102 (Processing) status code is an interim response used to
inform the client that the server has accepted the complete request,
but has not yet completed it.
but it has a caveat:
The server MUST send a final response after the request has been completed.
I'm not sure how to interpret the last sentence. Should the server avoid sending anything during the processing, and respond only after the completion? Or it only forces to end the response only when the processing terminates? This could be useful if you want to report progress. Send HTTP 102 and flush response byte by byte (or line by line).
For instance, for a long but linear process, you can send one hundred dots, flushing after each character. If the client side (such as a JavaScript application) knows that it should expect exactly 100 characters, it can match it with a progress bar to show to the user.
Another example concerns a process which consists of several non-linear steps. After each step, you can flush a log message which would eventually be displayed to the user, so that the end user could know how the process is going.
Issues with progressive flushing
Note that while this technique has its merits, I wouldn't recommend it. One of the reasons is that it forces the connection to remain open, which could hurt in terms of service availability and doesn't scale well.
A better approach is to respond with HTTP 202 Accepted
and either let the user to get back to you later to determine whether the processing ended (for instance by calling repeatedly a given URI such as /process/result
which would respond with HTTP 404 Not Found or HTTP 409 Conflict until the process finishes and the result is ready), or notify the user when the processing is done if you're able to call the client back for instance through a message queue service (example) or WebSockets.
Practical example
Imagine a web service which converts videos. The entry point is:
POST /video/convert
which takes a video file from the HTTP request and does some magic with it. Let's imagine that the magic is CPU-intensive, so it cannot be done in real-time during the transfer of the request. This means that once the file is transferred, the server will respond with a HTTP 202 Accepted
with some JSON content, meaning “Yes, I got your video, and I'm working on it; it will be ready somewhere in the future and will be available through the ID 123.”
The client has a possibility to subscribe to a message queue to be notified when the processing finishes. Once it is finished, the client can download the processed video by going to:
GET /video/download/123
which leads to an HTTP 200
.
What happens if the client queries this URI before receiving the notification? Well, the server will respond with HTTP 404
since, indeed, the video doesn't exist yet. It may be currently prepared. It may never been requested. It may exist some time in the past and be removed later. All that matters is that the resulting video is not available.
Now, what if the client cares not only about the final video, but also about the progress (which would be even more important if there is no message queue service or any similar mechanism)?
In this case, you can use another endpoint:
GET /video/status/123
which would result a response similar to this:
HTTP 200
{
"id": 123,
"status": "queued",
"priority": 2,
"progress-percent": 0,
"submitted-utc-time": "2016-04-19T13:59:22"
}
Doing the request over and over will show the progress until it's:
HTTP 200
{
"id": 123,
"status": "done",
"progress-percent": 100,
"submitted-utc-time": "2016-04-19T13:59:22"
}
It is crucial to make a difference between those three types of requests:
POST /video/convert
queues a task. It should be called only once: calling it again would queue an additional task.
GET /video/download/123
concerns the result of the operation: the resource is the video. The processing—that is what happened under the hood to prepare the actual result prior to request and independently to the request—is irrelevant here. It can be called once or several times.
GET /video/status/123
concerns the processing per se. It doesn't queue anything. It doesn't care about the resulting video. The resource is the processing itself. It can be called once or several times.
Kasey covers the main point.
The key idea in any web api: you are adapting your domain to look like a document store. GET/PUT/POST/DELETE and so on are all ways of interacting with the document store.
So a way of thinking about what codes to use, is to understand what the analogous operation is in a document store, and what this failure would look like in that analog.
2xx is completely unsuitable
The 2xx (Successful) class of status code indicates that the client's
request was successfully received, understood, and accepted.
5xx is also unsuitable
The 5xx (Server Error) class of status code indicates that the server is aware that it has erred
In this case, the server didn't make a mistake; it's aware that you aren't supposed to modify that resource that way at this time.
Business logic errors (meaning that the business invariant doesn't allow the proposed edit at this time) are probably a 409
The 409 (Conflict) status code indicates that the request could not
be completed due to a conflict with the current state of the target
resource. This code is used in situations where the user might be
able to resolve the conflict and resubmit the request. The server
SHOULD generate a payload that includes enough information for a user
to recognize the source of the conflict.
Note this last bit -- the payload of the 409 response should be communicating information to the consumer about what has gone wrong, and ideally includes hypermedia controls that lead the consumer to the resources that can help to resolve the conflict.
My solution was to wrap the failure handlers of any of our AJAX calls which will display a notification on the client when something fails due to 409 - this is all fine and works well alongside other 4XX and 5XX errors which use the same mechanism.
And I would point to this as the problem; your implementation at the client assumed that the status code was sufficient to define the problem. Instead, your client code should be reviewing the payload, and acting on the information available there.
That is, after all, how a document store would do it
409 Conflict
your proposed change has been declined because ${REASON}.
The following resolution protocols are available: ${LINKS[@]})
The same approach with a 400 Bad Request
would also be acceptable; which roughly" translates to "There was a problem with your request. We can't be bothered to figure out which status code is the best fit, so here you go. See the payload for details."
I would use 422. Input is valid so 400 is not the right error code to use
The WebDAV specification includes this recommendation
The 422 (Unprocessable Entity) status code means the server understands the content type of the request entity (hence a 415(Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions. For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.
I don't believe that's quite a match (although I agree that it sheds some doubt on 400
as an alternative). My interpretation is that 422
means "you've sent the wrong entity" where 409
is "you've sent the entity at the wrong time".
Put another way, 422
indicates an issue with the request message considered in isolation, where 409
indicates that the request message conflicts with the current state of the resource.
Ben Nadal's discussion of 422 may be useful to consider.
Best Answer
HTTP Status Codes are only designed to tell you about the status of your HTTP transmissions. They have no notion of "business rules."
Stick to 200 and 400. When you get a 400, you can retry the request or fail it. When you get a 200, your message is valid; you can then check the returned metadata for status information from your application (i.e. whether the payment succeeded or not).