43

We are developing a standard REST service using HTTP status codes as its response code if something went wrong. (e.g. invalid user input would return "400 Bad Request" to the client)

However, we felt that a more detailed error message would be useful for the client. (e.g. the invalid input error is due to X being a unrecognized parameter name)

We would like to be as faithful to the HTTP specs as possible, so after studying the specification in the RFC2616, we are thinking of putting the detailed error message in the HTTP Headers, specifically on the HTTP header warning field. It said on the RFC that:

The Warning general-header field is used to carry additional information about the status or transformation of a message which might not be reflected in the message. This information is typically used to warn about a possible lack of semantic transparency from caching operations or transformations applied to the entity body of the message.

There seems to be no restriction on using this header for other warnings (such as REST error message), even those that are unrelated with the cache warnings as per the original intention of this header. We like the semantic, and we planned to use the 299 warning code, which seems to fit the bill quite nicely:

299 Miscellaneous persistent warning The warning text MAY include arbitrary information to be presented to a human user, or logged. A system receiving this warning MUST NOT take any automated action.

So, given the invalid input error case presented on the top of this question, we're thinking of putting our REST error message like the following example:

HTTP/1.1 400 Bad Request
Warning: 299 ServiceName "Invalid input error: X is unrecognized parameter name."

Is this a good idea/practice? We also found that some services detailed this message in X-Warning header, but this seems to be not standard. We are wondering what would the hive wisdom of stackoverflow REST crowd think about this. Is there also any better/standardized practice for passing out detailed error messaging in REST responses?

Ibrahim Arief
  • 8,742
  • 6
  • 34
  • 54
  • Note: Warnings can accumulate between different requests in cache/proxy environments. Probably not an impact on a dynamic REST service, but something to keep in mind. – Barett Jun 26 '14 at 23:11
  • 1
    what did you guys do in the end? – dmportella Jul 12 '16 at 14:43
  • See also [draft-cedik-http-warning](https://datatracker.ietf.org/doc/html/draft-cedik-http-warning) and the issues discussion at [http-warning at GitHub](https://github.com/dret/I-D/tree/master/http-warning) – Jim Grisham Jan 16 '22 at 21:04
  • There appears to be a standards-track RFC purpose-made for this sort of thing: [RFC 7807 Problem Details for HTTP APIs](https://datatracker.ietf.org/doc/html/rfc7807) – Jim Grisham Jan 16 '22 at 21:30

7 Answers7

17

Why not just change the reason phrase? That's what it is there for. The "Bad Request" text is just the default. If you want to include more information then use the response body. The HTTP spec says you SHOULD include a response body with details of an error.


UPDATE

Based on a more recent reading of RFC 7231 and related material, it appears the only valid reason for changing the reason phrase is to localize the text, not to provide a more specific meaning. Sorry about that.

Darrel Miller
  • 139,164
  • 32
  • 194
  • 243
  • 1
    Do both. Changing the Reason-Phrase is good for machine clients, so e.g. you can write automated tests that check for specific conditions without having to parse HTML etc. And yes, a response body with details is a SHOULD, which means "do it if you want to call yourself fully interoperable". – fumanchu Jul 13 '11 at 14:25
  • 1
    Wow, brilliant approach, I honestly didn't know that we could customize the reason phrase. The legacy system we had right now didn't put any detailed error message in the response body, and we're constrained by some external legacy clients that might not expect a change in the body, so we tried to kept the external change as minimal as possible by sneaking the message in the header. Based on this suggestion, we end up implementing all three approaches, and let the output be customizable, many thanks! – Ibrahim Arief Jul 13 '11 at 15:38
  • 2
    Some clients (at least NSHTTPURLResponse) do not provide access to the reason phrase. Relying on it solely will cause problems for those clients. The warning header field should be universally accessible. – Jeffery Thomas Dec 08 '13 at 02:40
  • @JefferyThomas. There are some clients that don't let you access the HTTP headers at all, should we stop using those too? – Darrel Miller Dec 08 '13 at 08:33
  • 1
    If clients that have no access to the HTTP header are likely to use your system, then relying on it solely will cause problems for those clients. In that case the message body would need to be structured in such a way as to provide response status and detailed error messages. This doesn't mean you shouldn't use the HTTP header, you just should not rely on it solely. Just out of curiosity, which clients have you run into that do not have access to the HTTP header? – Jeffery Thomas Dec 08 '13 at 14:41
  • 1
    @JefferyThomas Yes, I phrased my question badly. I was just curious how far you would go in adding redundant information into your responses to support client software that can't be bothered to implement a spec that is 14 years old and supported by almost every network connected device on the planet. And personally, if reasonphrase isn't sufficient I use json-problem to return additional information. http://tools.ietf.org/html/draft-nottingham-http-problem-04 – Darrel Miller Dec 09 '13 at 00:14
  • Sorry, I guess I should have been clearer also. iOS is an area that I've been focusing on lately, so I tend to think of it by default. If you have no expectation of iOS clients, then the limitation of `NSHTTPURLResponse` is not of any concern. – Jeffery Thomas Dec 09 '13 at 11:48
4

Wherever you put your feedback, whether in the message body (content) or in a Warning header, be careful to avoid giving any information that might be helpful to an attacker doing penetration testing on your system.

Sometimes less info is better.

james.garriss
  • 12,959
  • 7
  • 83
  • 96
2

I'm in favor of using headers for warning only when the request succeeds in general.

For example a service that get's a user's details, but some of the details come from a third party which often goes down. In our case it was appropriate to leave that section of the user data blank, but show a warning to the user that some data is missing.

So the request returned a 200 Success with a payload that contained everything we could retrieve, but then had warning headers that described the error for the rest.

CaptRespect
  • 1,985
  • 1
  • 16
  • 24
1

If this proposal is accepted, it presents an alternative for sending detail error messages. [https://datatracker.ietf.org/doc/html/draft-nottingham-http-browser-hints]

Despite it being an I-D, it's fairly stable lately, and I see no problem with building your own implementation. (I have done.)

Community
  • 1
  • 1
Matty K
  • 3,781
  • 2
  • 22
  • 19
  • See [here](https://github.com/Jaymon/endpoints/issues/113#issuecomment-1013950899) for a link to another, different, proposal. It refers to [draft-cedik-http-warning](https://datatracker.ietf.org/doc/html/draft-cedik-http-warning) and the issues discussion at [http-warning at GitHub](https://github.com/dret/I-D/tree/master/http-warning). – Jim Grisham Jan 16 '22 at 21:07
  • There appears to be a standards-track RFC purpose-made for this sort of thing: [RFC 7807 Problem Details for HTTP APIs](https://datatracker.ietf.org/doc/html/rfc7807) – Jim Grisham Jan 16 '22 at 21:30
1

I'm in favour of the general approach. We should assume that the client developer is in a different team from the service developer, maybe in a different timezone etc. Possibly even a different company. It's no good just returning a "no that's a bad request" response, how can the client fix the problem.

So philosophically: tell the client about the things they have a responsibility to fix. Errors that are purely the scope of the server (eg. database connection error, or some logical problem) it's fair just to return a 500 error. And here I would not send any detail back, we don't want to expose details of our internal implementation to the client.

Until now I've been returning data in the body of the response, using JAX/RS:

return Response.status(400).entity("some message here").build();

I'm thinking that your use of headers may actually be a cleaner appraoch.

djna
  • 54,992
  • 14
  • 74
  • 117
1

The Warning HTTP header is likely to be deprecated in 2022 due to lack of client support.

(It could always be reactivated or repurposed in the future, though, so I would be quite wary about changing the semantics outside of a closed ecosystem.)


There appears to be a standards-track “Proposed Standard” RFC purpose-made for this sort of thing:


Although it hasn’t been updated since early 2021, there is also draft-cedik-http-warning - Communicating Warning Information in HTTP APIs under discussion on GitHub.

Jim Grisham
  • 384
  • 3
  • 11
0

429 Too Many Requests (RFC 6585) The user has sent too many requests in a given amount of time. Intended for use with rate limiting schemes.

Since you are allowing one request per lifetime, you are implementing a rate limiting scheme, so this is the appropriate HTTP response.

You can also (and are encouraged by the HTTP spec) to customize the HTTP Response body, so you can change "Too Many Requests" to any explanation you want.

Neil Davis
  • 238
  • 1
  • 5