Long running ReST requests and status endpoints

This is a very brief post about how to handle long-running requests in your ReST API. Sometimes, requests can't be handled immediately and your API should return information to the caller so that they can check the progress.

If you have a ReST API endpoint that takes a long time to process requests, it is common practice to return a 202 Accepted response and include a header with a link to an endpoint that gives the status of the operation.

For example, a caller POSTs this request:

POST https://api.yourservice.com/bigthing HTTP/1.1
Accept: application/json

{
"field": "value"
}

... and the server responds with:

HTTP/1.1 202 Accepted
Operation-Location: https://api.yourservice.com/operations/123

Now your callers can call that polling endpoint to check the status.

But what return code should https://api.yourservice.com/operations/123 return? Should it return a 200 OK with a resource describing the status of the job, or should it return another 202 Accepted if the job is still running and then a 200 OK (or 201 Created)?

There is some some conflicting advice around this. Some of it says that the polling endpoint should return 202 Accepted until the resource is ready. One such page is on the Azure architecture patterns site, named: Asynchronous Request-Reply pattern. It has this diagram:

In my opinion, this is the wrong advice (I submitted a pull request to correct it).

👌 Update January 2022
The PR was accepted and that document has now been updated.

The HTTP return code should be for the resource that is being returned, and not for some resource that was previously requested. So, the resource being asked for is 'the status of the original request', and what's being returned is a resource describing 'the status of the original request'. A 202 Accepted is saying 'I accept your request for the status of the original request'

The HyperText Transfer Protocol (HTTP) 202 Accepted response status code indicates that the request has been accepted for processing, but the processing has not been completed (#)

The Microsoft API guidelines page, in section 13.2.7 has the right advice. It says that the polling endpoint should return a 200 OK. For the simple example above, the caller calls the polling endpoint:

GET https://api.yourservice.com/v1.0/operations/123
Accept: application/json

... and the polling endpoint returns

HTTP/1.1 200 OK
Retry-After: 30

{
"createdDateTime": "2021-12-24T09-00-00.0Z",
"status": "running"
}

... the client calls it again after 30 seconds, and gets:

HTTP/1.1 200 OK
Content-Type: application/json

{
"createdDateTime": "2021-12-24T09-00-30.0Z",
"lastActionDateTime": "2021-12-24T09-00-00.0Z",
"status": "succeeded",
"resourceLocation": "https://api.yourservice.com/bigthings/42"
}

In summary, long running operations in a ReST API should provide polling endpoints. The polling endpoints are no different to other endpoints and should follow the same standards used for any other request for a resource. Be aware that some online articles can be confusing or contradictory, particularly when they deviate from the ReST guidelines. Following the ReST guidelines ensures a consistent experience for your users and they'll thank you for it (only joking, they just won't moan about it being wrong!)

🙏🙏🙏

Since you've made it this far, sharing this article on your favorite social media network would be highly appreciated 💖! For feedback, please ping me on Twitter.

Leave a comment

Comments are moderated, so there may be a short delays before you see it.

3 comments on this page

  • Paul Jackson

    commented

    Thank you for the informative article, brilliant. I work with C++ and EMS/Rad Server. I've been trying for some time to understand how I could use long lived logic in a ReST server, without the need to write a separate server to handle complex computations. This article has helped me in understanding the concepts of ReST better, and has answered the question. Thank you for writing it. I have learned some new today about the concepts of ReST services ! Please feel free to contact me anytime, I invite any conversation where I can become a better programmer or maybe be helpful in some way. Best, -PJ

  • Steve

    commented

    Jim, 302 is a redirection. This isn't applicable (IMO) for the request of the resource for the status of the original request. We're no longer asking for the resource, we're asking for the status. The status is ready immediately. The status may or may not contain a link to the original resource, depending on whether it's ready or not.

  • Jim

    commented

    Perhaps I missed it, but where do you discuss the 302 "Found" code? Makes sense (as much as possible with HTTP) that the 302 is use to indicate the resource/operation is ready. I expected your last code block to return 302 instead of 200, and the resourceLocation indicates where to get the final response for the request.

Published