219

I'm developing a RESTful API in which http://server/thingyapi/thingyblob/1234 returns the file (aka "blob") associated with item #1234 to download. But the request could be made before the file has been generated. It definitely will be available at a later time.

There's a batch process in the server that generates all the blobs. Item 1234 already exists and its data, other than the blob, is already available. The server just hasn't generated 1234's blob yet.

I don't want to return 404; that's for things that do not exist. This will exist, but hasn't been generated yet. Kinda like a YouTube video that's "processing." I don't think redirection codes would be proper either; there's no "other" URL to try.

What's the correct HTTP status code to return in such a case?

GlenPeterson
  • 4,866
  • 5
  • 41
  • 49
JCCyC
  • 16,140
  • 11
  • 48
  • 75
  • 3
    [Somewhat related](http://stackoverflow.com/questions/7730199/best-practice-for-implementing-long-running-searches-with-rest/7730452#7730452) – Rob Hruska Mar 20 '12 at 21:04
  • 7
    First, if thingy 1234 does not yet have any GET-able representation, in what sense does it exist as a resource (from the client's perspective)? The fact that, internal to the server there is a queued job to create 1234, doesn't seem to imply that resource 1234 exists. Second, where did the client get the URI .../thingyblob/1234? The server probably shouldn't have provided that URI to the client until the resource was actually GET-able. – Andy Dennie Mar 21 '12 at 14:16
  • 1
    A thingy has other properties that are worth getting other than the blob. It's only the blob that takes time to generate. Client gets those by, for example, http://server/thingyapi/thingy/1234 – JCCyC Mar 21 '12 at 16:29
  • 1
    possible duplicate of [Is it wrong to return 202 "Accepted" in response to HTTP GET?](http://stackoverflow.com/questions/4099869/is-it-wrong-to-return-202-accepted-in-response-to-http-get) – Gili Dec 11 '12 at 22:57
  • 4
    How about `204` "No Content"? Is indicates that the server has successfully processed the request and is not returning any content [at this time]. – Timo Jun 26 '18 at 08:33
  • 1
    The client requested a resource before the server was ready for that request. If you view this as a too-early request, that makes it the client's fault and `202 - Accepted` is the correct answer. If you view this as a too-late resource generation, it's the server's fault and `503 - Unavailable` is more appropriate. Either could be a correct answer. I think that the "try-again later" aspect is more of a 5xx thing than a 2xx thing, so I'd choose 503. – GlenPeterson May 26 '22 at 21:29
  • 1
    I've found one [public API](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/async-operations#create-storage-account-202-with-location-and-retry-after) (MS), and they are actually using 202 – Tomas Dec 27 '22 at 18:33
  • 1
    Does anyone else think that we need a significant update to HTTP Response Codes that we've been using for 20+ years? I've found them to be very limited and misleading (especially dealing with API responses). – Jeremy Holovacs Jun 12 '23 at 18:49
  • I second Jeremy's motion. – JCCyC Aug 02 '23 at 20:57

8 Answers8

99

The "problem", such as it is, is on the server side: the client has made a well formed request, but the server can not satisfy it. So I'm inclined to a "Server Error", 5xx status code.

Quoth RFC 7231 (the current HTTP standard, emphasis added):

The 5xx (Server Error) class of status code indicates that the server is aware that it has erred or is incapable of performing the requested method. Except when responding to a HEAD request, the server SHOULD send a representation containing an explanation of the error situation, and whether it is a temporary or permanent condition.

Note

  • "erred or is incapable of performing the request": despite their title of "Server Error", they are not just for server errors.
  • "temporary or permanent": these codes are suitable for temporarily unavailable resources, like yours.

Of the available codes, I'd say 503, "Service Unavailable" was the best fit:

The 503 (Service Unavailable) status code indicates that the server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay. The server MAY send a Retry-After header field... to suggest an appropriate amount of time for the client to wait before retrying the request.

Note:

  • "likely be alleviated after some delay": true for your case.
  • "temporary overload": not pedantically true for your case. But, it could be argued, were your server much faster, the batch processing would have already been done when the client made the request, so it is a kind of "overload": the client is asking for resources faster than the server can make them available.
  • Retrying is suitable for your service, so your reply ought to include a Retry-After value. You could provide as the value the estimated completion time of the next execution of the batch process, or the execution interval of the batch process.

Defining your own 5xx status code (591, for example), although permitted, would have the wrong semantics:

a client MUST understand the class of any status code, as indicated by the first digit, and treat an unrecognized status code as being equivalent to the x00 status code of that class

Clients would treat your own status code as 500, "Internal Server Error", which would not be right.

Community
  • 1
  • 1
Raedwald
  • 46,613
  • 43
  • 151
  • 237
  • 4
    I fail to see how it's better than 202: http://benramsey.com/blog/2008/04/http-status-201-created-vs-202-accepted/ – JCCyC Sep 06 '12 at 22:24
  • 4
    @JCCyC your blog makes a good case for returning a 202 in response to a request to create something (a POST or PUT). The question seems to be asking about what to return for a GET. – Raedwald Sep 06 '12 at 22:49
  • @JCCyC it could be seen as a different shade of not-ready-ness: imagine an ajax to that ressource, do you prefer 202 as a success status or 503 as an the error status? so you can see which meaning you prefer implicitly in the context of your app's reaction to the response – rloth Jul 27 '16 at 11:26
  • also i like the practical aspect of "Retry-After" that goes well with something being "not ready" – rloth Jul 27 '16 at 11:29
  • 4
    NB: "Retry-After" can also go with **`307 - TEMPORARY REDIRECT`** which is good if you want to force client side to wait elsewhere while your ressource is being "made ready" – rloth Jul 27 '16 at 11:36
  • 4
    This is not a problem with the server. 5xx codes should not be used. The use case is an expected and valid state of the system. Partially generated records are not the same as a partially functional server. There is no problem with the client either. They are asking for a valid resource that will exist at some point. 4xx codes should not be used. The server's response should be "OK, but I'm still working on it" (202 Accepted). – Jared Deckard Mar 07 '19 at 17:15
  • 2
    @JaredDeckard No, cannot agree with 202 - unless one changes the documentation for the endpoint. If the endpoint is "give me x", then no, we will not give you x, and giving x is not a "process" that can be completed later. But if the endpoint is described as "preparing representation x of resource y" then ok, the server is preparing a resource, which does already exist, in the form requested by the client, but it's not ready yet. However I would like to add that 5xx errors doesn't mean there is something wrong with the server in the sense you seem to imply. 503 means the client *should* retry. – AnorZaken Sep 07 '21 at 10:36
  • ....for example 505 status code indicates that the server does not support, or refuses to support, the major version of HTTP that was used in the request message. This is not a server error, nothing on the server is broken. So 5xx errors does not mean the server (or anything else for that matter) is "broken", it means there is some kind of problem, and most likely the nature of the problem is such that it should be fixed on the server-side rather than on the client-side. That being said I think OP is trying to do too much here, and 404 is correct + a way to query status via another endpoint. – AnorZaken Sep 07 '21 at 10:45
  • The service is not unavailable, the resource is unavailable. Not the same thing. – Foumpie May 26 '23 at 11:12
90

I suggest 202 - Accepted. From the documentation:

The request has been accepted for processing, but the processing has not been completed. [...] Its purpose is to allow a server to accept a request for some other process (perhaps a batch-oriented process that is only run once per day)

Tim Ludwinski
  • 2,704
  • 30
  • 34
matsev
  • 32,104
  • 16
  • 121
  • 156
  • 113
    -1: This would make sense for the request which initiates the process that eventually creates "thingy #1234", but not for the GET request issued afterwards for "thingy #1234" itself. In particular, a 202 suggests that as a result of the GET request, the service will send the data for "thingy #1234" at a later point in time. This is simply not correct. – Sam Harwell Oct 14 '14 at 22:10
  • The documentation clearly states: "The request might or might not eventually be acted upon", so there is no obligation for a GET to send data later if 202 is reported. – Remy Lebeau Oct 15 '14 at 14:34
  • 10
    It also says: "The entity returned with this response SHOULD include an indication of the request's current status and either a pointer to a status monitor or some estimate of when the user can expect the request to be fulfilled.", so this would be a good way to let the client know that the blob is not ready yet, and a way to find out when it is ready. – Remy Lebeau Oct 15 '14 at 14:37
  • 6
    I would argue that "accepted for processing" indicates that you're saving the request to be acted on later. If it's just being ignored, you should return a 4xx or 5xx code to indicate to the client that they might want to try again. – Luke Oct 20 '16 at 15:17
  • 5
    102 (processing) seems also a reasonable choice sometimes even though it is in webdav spec. – akostadinov Dec 02 '16 at 10:19
  • 9
    Can't disagree more with this answer. The server is not returning anything, or planning to (not doing any processing because of this request - which it anyway should not for a GET). As such, the resource is in some fashion not available to the client. This should be treated as an error so no 2XX code is appropriate. Something in the 4XX or 5XX space. The request has *not* _"been accepted for processing"_, the request is in practice being discarded – Adam Oct 21 '18 at 14:15
  • 1
    The anser by @Raedwald is a much better approach – Juan Fuentes Jul 25 '19 at 15:41
45

I think that 423 - Locked can be used for this purpose:

The 423 (Locked) status code means the source or destination resource of a method is locked. This response SHOULD contain an appropriate precondition or postcondition code, such as 'lock-token-submitted' or 'no-conflicting-lock'.

Fernando Ortega
  • 696
  • 6
  • 15
  • 1
    Excellent answer! I wonder why it doesn't have more upvotes. – lex82 Jun 03 '16 at 08:56
  • 19
    Perhaps because it is a WebDAV HTTP code ? – Stephan L Aug 18 '16 at 14:49
  • 2
    From akka-http there is StatusCode RetryWith = reg(c(449)("Retry With", "The request should be retried after doing the appropriate action.")) where the action would be wait and retry – ozma Mar 29 '18 at 07:37
  • 3
    In many ways I agree with this. I have a similar situation (in my case searching from an index which may not yet be populated). Semantically, I think this is correct. However, the RFC for 423 states _"This response SHOULD contain an appropriate precondition or postcondition code, such as 'lock-token-submitted' or 'no-conflicting-lock'."_ Not sure how to apply that here. And personally I'd go with 409 Conflict, but that's been downvoted without comments - not sure why? – Adam Oct 21 '18 at 14:11
  • @Adam from the name of the status it becomes clear that it should only be used if the request data conflicts with the version of the data available on the server. No wonder it's indicated everywhere that the most typical use case of this status is an irrelevant **PUT** request. For example, an attempt is made to update some resource with data that is no longer relevant (a more recent version of the data has already been written by one of the previous requests) – Nikita Kobtsev Mar 20 '22 at 10:30
  • @NikitaKobtsev: I'd argue the same applies. You are asking for data that is still being processed/created. it's not currently (yet) in a state to be returned. So the request data (id or whatever) conflicts with the version on the server (only half ready) – Adam Mar 21 '22 at 09:04
  • @Adam a 409 Conflict means an unresolvable conflict and means that the request that was sent should NOT be sent again. It is not for nothing that the status is from 4xx, but the client isn't to blame that our resource cannot always give all the data. It shouldn't be 4xx. I like the 201, but it means we are guaranteed to process the request, which is not a use case. I agree with *skalee* that a Retry-After header that only supports 3xx and 503 is must-have here. I like 503 more. Out of 3xx only 302 is good, but still was designed for a different use case – Nikita Kobtsev Mar 22 '22 at 11:28
  • @NikitaKobtsev: You say _"409 Conflict means an unresolvable conflict and means that the request that was sent should NOT be sent again"_ but that's not true. The RFC (https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.8) says _"This code is used in situations where the user might be able to resolve the conflict and resubmit the request."_ The way I see it, the user can resolve the conflict by waiting until the file is generated. 201 only works, in my opinion, if you can later fulfill the request without a new request (e.g. send them the file somehow once it's ready) – Adam Mar 22 '22 at 15:01
  • @Adam I see it like the time of request shouldn't be the source of conflict. I think that this status was designed to indicate an irrelevant body/headers of the request. So it's totally correct in terms of the API design, but it's irrelevant. And also in my opinion if the service doesn't include a Retry-After, when asks to make a request again after some time, that's the wrong reply. – Nikita Kobtsev Mar 22 '22 at 18:01
  • Nothing really fits 100%. 201 is definitely wrong, unless you will fulfil it later. So, 409 is the closest. The way i look at it, it should not be an automatic retry but the user should be informed and invited to take action. That action could be waiting and trying, or fixing the data or whatever. – Adam Mar 23 '22 at 07:53
  • The problem with a 4xx code is that they imply that "The client should not repeat this request without modification." Source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400 "Not Ready Yet" is a server-side issue, so it has to be a 5xx code and 503 is the one, with no redirect and no caching. – GlenPeterson May 26 '22 at 21:10
31

I don't want to return 404; that's for thingies that do not exist.

The URL doesn't correspond to a request for a thingy.

http://server/thingyapi/thingyblob/1234

The client is requesting a thingyblob, which doesn't exist. If it existed, you would give it to them.

404.

funroll
  • 35,925
  • 7
  • 54
  • 59
  • 4
    I'm glad someone said this! I can't believe there are so many people that think `503` is an appropriate response. Not to mention some of the other strange suggestions. – Jason Desrosiers Apr 29 '15 at 06:36
  • Although I agree that a 404 is the most appropriate response here, it doesn't answer the OP's question how to indicate when the thingy is available :-). I think the Retry-After field seems the best candidate but it can only officially be used for 503 and 3xx codes. @Jason: I think that explains some of the strange suggestions. – Ron Deijkers Aug 14 '15 at 13:03
  • 2
    I think this is the best answer. You are allowed to return a body in a 404 response. The body could indicate that the thingy will be available at a later date. Or use Retry-After header as well. The standard needs to be stretched a bit here because it doesn't cover this case nicely. – WW. Oct 07 '15 at 00:30
  • 6
    People have become too acclimated to 404 meaning page not found that they can't logically dissociate that when in the context of an API. – The Muffin Man May 07 '17 at 20:15
  • 3
    This is sooooo 404. Thingyblob does not exists yet, or ever.. For http its irelevant if it will ever be available. At the moment it does not exist, and its 404. When it will be available is another problem, which can be solved by pushing a mesage from server to client sayin thingyblob: 1234 available. Perform a get again and voila.. – 100r May 21 '19 at 15:01
  • 1
    While this is techical correct, we need to return additional info in the response body or headers, to somehow differentiate it from "normal" 404 responses, in which we will not try again later. I found it easier to go with the 202 approach. – alfoks Dec 11 '20 at 14:19
22

Another option: 503 - Service Unavailable.

Brian Kelly
  • 19,067
  • 4
  • 53
  • 55
  • 5
    [According to W3C](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) it's not what you want to say to client (although it means "come again" in some manner): "The server is currently unable to handle the request due to a temporary overloading or maintenance of the server. The implication is that this is a temporary condition which will be alleviated after some delay. If known, the length of the delay MAY be indicated in a Retry-After header. If no Retry-After is given, the client SHOULD handle the response as it would for a 500 response." – skalee Jan 21 '13 at 05:13
  • 8
    Service is not unavailable, service is available but processing is not complete. So 503 is probably not a good idea. – Ishtiaque Khan Mar 11 '18 at 17:23
21

Since your resource is not ready, you probably know when (approximately) it will be available and when client may retry his request. This means you might want to utilize Retry-After header. This header is valid with 503 (Service Unavailable), which means whole site is down for maintenance, and 3xx (Redirection) responses.

In my opinion 302 (Found) with Retry-After header would be the best option, but I am not sure if Location field of response header can be equal to request url. It's circular redirect, anyway.

skalee
  • 12,331
  • 6
  • 55
  • 57
  • 3
    Even if it is allowed, if the client hasn't implemented support for the Retry-After header then a 3xx Redirection to the same page might eventually end in a 503... (optionally with a Retry-After header of course) – Ron Deijkers Aug 14 '15 at 13:19
  • 1
    Retry-After is also valid with HTTP 429 "Too Many Requests", added by RFC 6585 (April 2012). This might be appropriate if the reason for the resource not yet being ready is the client has been giving the server too much work to do. – Silas S. Brown Oct 05 '17 at 09:29
15

409 Conflict

Indicates that the request could not be processed because of conflict in the request, such as an edit conflict in the case of multiple updates. [Source Wikipedia.]

This could be appropriate.

If you cant fulfill the request by returning the data - then its not a success. I think 202 suggests the server has queued the request and it will fulfill the request later. But in your case, the request is for data now and has failed. If you retry later it is a different request.

I think you have a conflict.. you want the data.. but its being edited / updated. This would also be the case if Thingy1234 already existed and had been successfully downloaded before, but now was in the process of being edited was was unavailable whilst the edit was taking place.

J Moore
  • 171
  • 1
  • 2
  • 4
    Not sure why this got voted down. Seems like the right answer to me. From the RFC: _"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._" You asked for a resource which the server cannot return because the server is in the process of updating that resource - i.e. due to the current state of the resource. The client can resolve this by waiting and resubmitting – Adam Oct 21 '18 at 14:10
  • 3
    @Adam I think the implication in "user might be able to resolve the conflict" is that something about the resubmission would be different, other than just waiting. – Holistic Developer Apr 22 '20 at 20:29
-1

501 - Not Implemented

Exactly like how it sounds. A feature that is not yet implemented, but implies future availability.

Here is a link to a summary of 5xx errors.

Bruce P
  • 19,995
  • 8
  • 63
  • 73
Dan
  • 506
  • 5
  • 18
  • 6
    For this question it sounds like the feature itself exists, but the item being requested does not. – Luke Oct 20 '16 at 15:19
  • @Luke 501's description from the link in my answer, '...it lacks the ability to fulfill the request. Usually this implies future availability'. This is fulfills exactly what the OP was asking for. Regardless of whether or not the data is there on his servers or DB. The ultimate result is that it is not accessible via the API for now. Therefore the API can't fulfill the request, but would like to imply that it will be available in the future via the http code. – Dan Oct 20 '16 at 18:00