1

We have an API that allows clients to POST some request which takes some time to complete, so the API simply places it on a message queue and returns a 202 (Accepted) and a new GUID in the body.

The client then can use this GUID to call a GET endpoint to check on the status of their POST request.

Suppose they call the GET so quickly after the POST that we have zero information about its status (usually because it is still in the queue). Should we return a 404 (Not Found) or some other status?

Someone on our team suggested 204 (No Content) but that seems inappropriate to me.

4
  • 1
    What do you mean with having zero information about its status? If it is a valid GUID, you should at least be able to tell that it is queued for processing. Dec 5, 2023 at 11:58
  • @BartvanIngenSchenau not necessarily, perhaps that guid has not yet been persisted anywhere and exists only in the queue
    – JoelFan
    Dec 5, 2023 at 13:16
  • 3
    Ultimately, this is a question about the consistency guarantees you want to offer in this distributed system. If you give up (aka "eventual consistency"), then I think a 404 response would be appropriate because that server doesn't yet know about the job. But it wouldn't be too much trouble to at least offer read-your-writes consistency to avoid this problem: persist information about the job before responding that it was "accepted". This also avoids jobs getting lost if the server crashes. All mainstream DBs can do this.
    – amon
    Dec 5, 2023 at 16:00
  • 4
    If you have no information about the actual GUID, how can you distinguish it from me giving you a wrong GUID, which I assume should return 404?
    – gnasher729
    Dec 5, 2023 at 16:53

3 Answers 3

10

First off, returning 404s when a resource is not found is controversial. The issue with it is that it can be challenging to distinguish between a bug (e.g. the wrong URI base) versus having a valid path to a resource that doesn't exist. I am a little ambivalent about that idea, but I tend to accommodate this viewpoint.

Leaving that aside, I don't think the design you are describing is very robust. I spent quite a few years wrangling queuing systems and one of the main things I am quite sure of is that you should never depend on queuing systems as the sole record of anything that matters. There are simply too many ways that messages can be lost and once they are, you will have no record they were ever created aside from logs (potentially.) Queues are a great way to distribute and manage work, but they are not reliable storage mechanisms. Don't let terms like 'guaranteed delivery' lull you into a sense of security. There are many caveats to such claims, and there's no protection from defects or misconfigurations.

What I would recommend is that you create a record for the UUID in some sort of DB where, unlike queues, reads are safe (i.e. do not change any state). Then write the message to a queue. This eliminates the possibility of the client requesting the status of the UUID before it is 'known'.

4

First observation: the nature of the problem here is that, at the point where we receive the GET request for the check-on-the-status resource, we cannot discriminate between the case where the GUID is one that your system issued (but the processing hasn't caught up yet) and the case where some client just made up a GUID.

The heuristic I use in that case: we are not obligated to produce a good experience for clients that are trying to abuse our server. Since the paying customers using the system as intended are our priority, we design the experience that is good for them.


For choosing status codes, an important idea to integrate into your API design is: status codes are meta data of the transfer-of-documents-over-a-network domain. They communicate coarse grained response semantics to general purpose HTTP components (browser, proxies, etc).

Status codes are not designed to be used for describing the semantics of the representation of the resource. That information normally belongs in the representation of the document itself.

In other words, your resource representations are documents; your document schema needs to be flexible enough to describe the edge cases of your business domain in addition to "the happy path", and you use status code 200 to indicate that the response body is the current representation of the resource, which is to say the current version of the flexible document.

In most common cases (which I believe includes your specific problem), returning 200 with useful information in the document is the right choice to make.


The important REST constraint here is "uniform interface"; all HTTP resources should understand messages the same way. We should not be creating resources where the semantics of message elements (including status codes) are changed.


That said - the world won't come to an end if you send a 404 with a representation of the error situation instead of a 200.

Note that in either of these cases, you can communicate to the general purpose client that the current answer is only valid for a short period of time via caching headers.


An alternative approach is to communicate to the general purpose client that the request should be retried after some time interval.

In that case, you probably want to consider a 307 Temporary Redirect, with a Location header that points to the same URI and a Retry-After header describing the minimum time that the general purpose client should wait before issuing the next request.

You'll still want to use some care in designing the body of the response, as there are no strong guarantees that the client will re-issue the request.


Another element that you might want to consider is including a timestamp in the URL for the check, as a mechanism for tracking when the original request was submitted, so that you can discriminate between "please continue to be patient" responses and "it should not take this long, please contact support" messages.

3

Do you have way to query the queue for that GUID?

If you don't, I don't think anything else than a 404 is appropriate, because you can't differentiate between the GUID plainly not existing and the GUID being in the pre-processing queue

If you can query that queue for the GUID, and you know it's still in the queue, I would be more inclined to return a 409 - Conflict

From MDN:

The HTTP 409 Conflict response status code indicates a request conflict with the current state of the target resource.


Someone on our team suggested 204 (No Content) but that seems inappropriate to me.

A 2xx indicates a successful request, of which it's not

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.