Then we have the more esoteric advices:
Thanks!
It seems like the "general guidelines" are:
- If using a custom media type: you can (should?) design error handling into the media type itself [Mike].
- If using a standard media type like plain XML, JSON or (X)HTML: find a way to encode error messages.
- Make sure its straight forward to locate it - using specific XML elements/namespaces, certain JSON properties or certain HTML classes/identifiers.
- The client should know that it needs to look for the error information since it got 4xx or 5xx. Thus it wont suddenly try to decode an error response as, for instance, a sales order.
What should we do for binary response types such as image/jpeg or application/pdf, or for media types where there is no reasonable way to encode an error message?Also, what about HTTP methods for which "the server MUST NOT return a message-body in the response?" like HEAD[1]?
- No one seems to implement a specific media type for error information.
- That makes somewhat sense to me; the client would have to include that media type in the "Accept" header in each and every request it makes. That would not be unreasonable but slightly odd since I assume most clients (and devs) are used to depend on one single media type.
This was a really good catch, but it brings up a potential "double bind." If an Accept header[2] is used and is specified to be, for example, "application/pdf" is it valid to return a message body of type "text/plain" when an error occurs?It would seem on status codes 4xx[3] and 5xx[4] that responses "SHOULD include an entity containing an explanation of the error situation" (expect for HEAD, there's that HEAD exception again.) Except[5] "All responses to the HEAD request method MUST NOT include a message-body, even though the presence of entity- header fields might lead one to believe they do. All 1xx (informational), 204 (no content), and 304 (not modified) responses MUST NOT include a message-body." So how do we return error messages in those cases? And can the entity message body differ from that which was requested via the Accept header when there is an error situation?
Then we have the more esoteric advices:
- The client may not be able to access to returned status code, so make sure it is possible to detect error conditions by looking at the payload alone.
-MikeWasn't the mentioned use-case for this to be JSONP? Are there other valid use-cases where status codes are not available?If no and given that JSONP is a hack (albeit a generally recognized and accepted hack) wouldn't that mean it shouldn't be used for general advice?And is it okay that we have a bunch of different ways to handle error presentation, instead of one accepted way? It doesn't sound like there is any commonality in the way people are returning errors so it seems errors will always get handled via a custom client, not via a standard client. Basically this feels like "Error Tunneling" to me, no?A potential way that nobody mentioned that I think would work in all cases where headers are accessible (and should be combined with appropriate HTTP status code) would be to have an "Error-Description" header? Would this work, or if not why not?
Well, the HTTP response status code is still workable in both
situations. My feeling is that the status code is almost always the
best way to pass error info anyway.
Thanks. That was my gut feeling too.Still, I can't help but want to explore those cases where it isn't the best way to pass error information. Or more precisely, where status codes are not *sufficient*.For example, let's assume I tried to access a past bank statement as "application/pdf" via the API but the bank has rules that lock down statements when the account is not in good status. A "409 Conflict" would seem to be the right response code, but it doesn't tell my why my account is not in good status; it would be preferable to be told it's because the account is overdrawn vs. the State department has frozen the account, etc. (NOT speaking from experience on the latter here. :)So how do I pass back error description here? I could turn the error description into "application/pdf" but then intermediaries are certain not to be able to read it, if needed. Of course, without a standard for error descriptions that too is probably moot?
Absolutely. The accept header is not some sort of contract that the
server *must* abide by, it is information about what would be most
useful to the client. The server may respond with any media type it
sees fit regardless of what the client put in the accept header. That
means that clients should be prepared to receive responses of any
media type for any request (but they don't have to do anything
particularly useful with that responses). In an error response the
client is going to see the 4xx or 5xx status code and know that the
response is not what it wanted anyway, so the fact that body is not
the desired media type is probably entirely moot.
Again, that was my gut feeling too. But shouldn't this have been explicit in the spec? Of course that is moot too, at least until the next revision of the HTTP spec but who knows when that's likely, if ever.It seems reasonable to send error messages via "text/plain", but it feels wrong to return "text/plain" if the header is "Accept: application/json" or "Accept: application/pdf" only.An additional idea: Would it make sense for HTTP to (have) add(ed) an "Accept-Error" header which is like "Accept" but it instead specifies the media type expected for an error, and the default when the header is not specified would be "text/plain"? That way custom APIs could be explicit about how they expect errors to be reported and "(defacto-)standard" error message content types could potentially emerge.
I am not sure there are really a bunch of different ways to handle
errors. I think the general advice should be:
* Servers should communicate the fact that the request failed by
using the most appropriate HTTP response status code.
Check.
* Servers should use the body of the failure response to provide
commentary about the failure that might be helpful in debugging or
recovering from the failure. Such commentary should be encoded in the
media type the server thinks most useful.
Hmm. But that's likely the best we can do at this point, at least as far as the spec is concern.
* Clients should handle failure responses gracefully regardless of
the media type of the body.
Hmm. Not every client can be that robust; it would be impossible to anticipate every potential type even for the best clients unless you mean just give up rather than fail. Still, not the best, especially for AJAX as it might be hard to give the user an idea why things failed.
* User agents should (attempt to) apply generalized HTTP failure
recovery logic if possible. (Retrying the request with an authenticate
header field after receiving an `unauthorized` response, for example.)
Check.
* User agents may (attempt to) apply media type specific logic to
recover from failure as they see fit.
Hmm. Workable, but could it not be better by explicitly addressing error handling?
(with the exception of the JSONP, which i am happy to ignore).
Ditto.
A potential way that nobody mentioned that I think would work in all caseswhere headers are accessible (and should be combined with appropriate HTTPstatus code) would be to have an "Error-Description" header? Would thiswork, or if not why not?
That is an interesting idea. What value do you see that providing over
using the status code and a plain text body?
Greater consistency. For APIs that return content types that do not support error handling there is no current method to return an error description. Sure we could devolve to "text/plain" but that doesn't work for partial errors, i.e. a URL that returns a list of records but for which the URL's implied query results in zero records. In this case it would be nice to have "No records found for foo=1 and bar=2" in "Error-Description."Also, according to the HTTP spec for the Message Body[1] returning an error message in the message body would violate the spec in these cases given the "MUST NOT" wording:
"All responses to the HEAD request method MUST NOT include a message-body, even though the presence of entity- header fields might lead one to believe they do. All 1xx (informational), 204 (no content), and 304 (not modified) responses MUST NOT include a message-body."
-MikeSo my gut tells me that "Error-Description" and "Accept-Error" headers could be used in all cases vs. just in most cases and always being able to it the same way is where I see the value. Of course this is just a straw-man proposal; feel free to poke holes into it.
HTTP Status codes are meant to pass status information about HTTP, not about apps _running_ over HTTP.In HTTP, application information (including status details) is meant to be carried in the payload itself; usually the body.HTTP status codes are almost _never_ sufficient for carrying application-level error information.If passing error information is important to your application, use the payload (usually the body) for this and document it as needed, just as you do other application-level information. Using a unique media type design for each _type_ of application-level information is possible, but not recommended. Same applies to headers.HTTP was designed to offer archs & devs _possibilities_ in expressing app-level information, not _requirements_. For some this may be a frustration, but for most the opportunity to select the means that best suits your use case is an advantage of HTTP, not a shortcoming.
-MikeUnderstood, and this is helpful. This is basically describing a subset of the OSI model.But nothing you said addresses the fact that HTTP is currently ambiguous about how to pass back application errors, especially when the spec says that there MUST NOT be a message body is selected cases. The caveat in your comment "..use the payload (usually the body)..." illustrates this.I would also disagree with what I think you implied, that error information is no different than any other application level information. Error is one of two well-known binary states; success or failure. It would make sense to recognize that applications may need error information out of band from content and thus providing explicit support for errors in the protocol makes sense, at least to me.
correct. is that what you want to solve/change? to make HTTP non-ambiguous on this matter?
Yes, at least by extension. I was hoping to explore what it would look like.
so, you agree there are multiple ways to return app-level info. you don't like that and you want HTTP to "provid[e] explicit support for [app-level] errors in the protocol"do i have that right?
IF I understand what you are saying, I think the answer is "yes", but specifically for errors, not at this point any other app-level info.And not the semantics of errors but instead a method for the protocol to provide references to the errors. So no mixing of protocol and app, just acknowledgment in the protocol that there is a special case known as failure and that the protocol could help the app handle failures in a more expressive way.As an aside, I think of technology as an evolution that recognizes fundamental use patterns over time. For example, the C language didn't have a foreach() but C# added it as it simplifies a fundamental usage pattern and thus now eliminates a class of related logic errors. Recognizing that API errors exist and coming up with a good standard way to handle them via the protocol has benefits, imo.
you have interesting ideas that should be brought to the HTTPbis group.FWIW, i'm not so interested (in this list) to talk about changing the protocol but instead how to use the existing standard to solve current problems.regarding the subject of this thread (communicating app-level errors) i think we have uncovered more than enough options to work w/.
True all, with one exception: For me I only have time to actively follow a few lists, so either I talk about it here or I don't have an outlet. :)Also I think it's when people start trying to solve real world problems is when they actually recognize potential solutions hence why there is some value in generate to discuss on this list (although definitely not ad-nauseum; once identified it would be appropriate to take elsewhere.)
On Thu, May 31, 2012 at 12:20 PM, mca <m...@amundsen.com> wrote:What? HTTP *is* an application protocol. How could it's status codes
> HTTP Status codes are meant to pass status information about HTTP, not about
> apps _running_ over HTTP.
> In HTTP, application information (including status details) is meant to be
> carried in the payload itself; usually the body.
not be about the apps?
Do you really think that the 409 conflict status code is about HTTP
and not the app "running over http"?
I disagree. I have found that most clients can't do much of anything
> HTTP status codes are almost _never_ sufficient for carrying
> application-level error information.
with information beyond what is available in the status line except
record it for consumption by a human. There probably are cases where
this is not true they are exceedingly rare edge cases and should be
dealt with as such.
For example, let's assume I tried to access a past bank statement as"application/pdf" via the API but the bank has rules that lock downstatements when the account is not in good status. A "409 Conflict" wouldseem to be the right response code, but it doesn't tell my why my account isnot in good status; it would be preferable to be told it's because theaccount is overdrawn vs. the State department has frozen the account, etc.(NOT speaking from experience on the latter here. :)
Well, in this situation i would prefer a prose description of why the
account is locked. If the user agent accepts HTML i would send the
error description in HTML if not i would use plain text. There is
nothing the client can do to fix the problem so burying the
description of the situation in a machine readable format just makes
understanding the problem more difficult.
Exactly. But where is that prose consistently available? It's not if I'm doing AJAX, for example, as the user doesn't get to see it unless the client-side code displays it. Which is can't without headers for certain response status codes and certain verbs.
It seems reasonable to send error messages via "text/plain", but it feelswrong to return "text/plain" if the header is "Accept: application/json"or "Accept: application/pdf" only.
The real question is how are clients going to use the response. If you
are really just sending a human readable description of the error then
plain text or HTML seems most appropriate. If you are trying to convey
some information to allow the user agent to recover from the error
then you'll need a machine readable format.
Exactly. But currently it's ambiguous what will be returned and there's no way to inspect the response to be sure.
I'd be included to just put the error format in the accept header
field with a low q value.
Given the existing spec without extensions, yes, but that doesn't give the API any explicit guidance on the error mime types the client can handle; it would be valid to return a non-error with that mime-type.
Hmm. Not every client can be that robust; it would be impossible toanticipate every potential type even for the best clients unless you meanjust give up rather than fail. Still, not the best, especially for AJAX asit might be hard to give the user an idea why things failed.
I disagree. If you are interacting with the user synchronously and you
get a non-success response in a media type you don't understand you
can just display and "Unknown error occurred" with a details button
that show the user the full response body. If a human is not
immediately available you can do the same thing but just shove it in
the log file.
That's not a disagreement, that's the "just give up rather than fail" scenario I stated in the "unless..." :)IMO it would be nice to be able to do better.
Hmm. Workable, but could it not be better by explicitly addressing errorhandling?
Don't see any better way to do it. Recovering from errors is
application specific so it is going to be pretty difficult to
generalize.
I see a better way. The prose can be included in a header directly or via a link, i.e. http://example.com/error-descriptions/123.htmlFor complex error response, a response header could specify that it's returning a mime-type specified in the request format and/or it could provide a URL for that mime type in the case of responses that are not allowed to have a message body.None of this is application specific.
Also, according to the HTTP spec for the Message Body[1] returning an errormessage in the message body would violate the spec in these cases given the"MUST NOT" wording:"All responses to the HEAD request method MUST NOT include a message-body,even though the presence of entity- header fields might lead one to believethey do. All 1xx (informational), 204 (no content), and 304 (not modified)responses MUST NOT include a message-body."
Yeah, handling an error response to a HEAD request is a little weird,
but i am ok with that. If you want a detailed error response you can
always repeat the HEAD as GET.
-MikeBut not ok with it. And it's not just for HEAD but also for 1xx, 204 and 304 status codes. Which is why I persist. :)
a custom media type isn't well suited to displaying information to a
human, text/plain and text/html are
-MikeExcept (at least) for when the API is used for AJAX and the response needs control information to be processed by the client Javascript.
One of the problems may be that people have different expectations for the error handling.
Definitely! (But I think you can replace "error handling" with any topic every discussed by humankind and it would still be true! :)
2) A simple ajax style web page. I am no expert on ajax frameworks, but text/plain and text/html should be easy to show to the user. A well known JSON object with the error message would be just as good.
The "well known" part here is key albeit "well known" headers could improve this; see next.
thus there is nothing in HTTP core that can be generalized beyond the status codes.
Disagree (as I've previously said.) Selected headers could specific a error description for when a message body is not allowed (either as plain text or a URL) and a header could indicate a mime type for an error message when it would be more useful than text/plain or text/html.
Very well put, Mike.
A communication protocol is a set of rules about how to communicate. On top of these rules, an application has many other (business) rules and constraints that have nothing to do with communication. They apply to a monolithic version of the application as well. Enforcing these rules and constraints should not be done at the protocol (HTTP) layer.
Say your application handles purchase orders and no two purchase orders can have the same identifier. This constrain applies weather you are typing the purchase order directly into your mainframe or updating it remotely via a HTML form. A duplicate id is an application logic error, not a communication error, so you should not use a HTTP error code to signal it. The communication was done correctly. The server received and understood the message. The protocol is working. A HTTP error code would be akin of telling a person “Sorry, I cannot understand you” on the phone when what you mean is “Sorry, but I cannot do what you are asking”.
I agree that rethinking the communication is such a way that you don’t need to resort to HTTP error codes to signal business logic violations is often non-trivial, but it is well worth the effort, IMO.
Ferenc Mihaly