RFC 7807

Problem Details for HTTP APIs

πŸ“… published March 2016, from ietf

0. Title Block Tea β˜•πŸŽ€

Okay bestie, let's get this tea spilled before we get into the good stuff πŸ’…. This RFC is RFC 7807: Problem Details for HTTP APIs πŸ¦‹, written by M. Nottingham (Akamai) and E. Wilde 🫢. It's a Standards Track document, published in March 2016, and its ISSN is 2070-1721 🌸. It doesn't obsolete or update any other RFCs, so it's giving fresh start energy ✨.

1. Introduction 🌈

Okay so, HTTP [RFC7230] status codes are sometimes just not enough to explain what went wrong, and that's lowkey a problem 😭. A human on a web browser can get an explanation in an HTML [W3C.REC-html5-20141028] response body, but non-human consumers of so-called "HTTP APIs" usually can't, and that's the whole gap we're fixing πŸ”₯.

This spec defines simple JSON [RFC7159] and XML [W3C.REC-xml-20081126] document formats for exactly this purpose 🧚. They're built to be reused by HTTP APIs, which can name their own distinct "problem types" based on what they need πŸ’–.

So API clients can get both the high-level error class (from the status code) and the finer-grained details of the problem (from one of these formats) ✨. Iconic combo, no cap πŸ‘‘.

Let's say a response tells the client that their account doesn't have enough credit πŸ’Έ. The 403 Forbidden status code might be deemed most appropriate, because it tells HTTP-generic software (like client libraries, caches, and proxies) the general meaning of the response πŸŽ€.

But that doesn't tell the API client enough about why the request was forbidden, what the account balance is, or how to fix it πŸ™ˆ. If those details go in the response body in a machine-readable format, the client can handle it properly, like triggering a transfer of more credit into the account πŸ’œ. Main character energy for real πŸ¦‹.

This spec does that by identifying a specific type of problem (like "out of credit") with a URI [RFC3986] 🌸. HTTP APIs can either nominate new URIs under their control, or reuse existing ones πŸ“.

Problem details can also include other info, like a URI that identifies the specific occurrence of the problem (basically giving an ID to "The time Joe didn't have enough credit last Thursday" πŸ’€). That's super useful for support or forensic purposes πŸ•΅οΈ.

The data model for problem details is a JSON [RFC7159] object. When it's formatted as a JSON document, it uses the "application/problem+json" media type ✨. Appendix A explains how to express them in an equivalent XML format, which uses the "application/problem+xml" media type 🌈.

Note that problem details are (naturally) not the only way to convey the details of a problem in HTTP πŸ™ƒ. If the response is still a representation of a resource, for example, it's often better to describe the relevant details in that application's own format 🫢. And in lots of situations, there's already an appropriate HTTP status code that doesn't need extra detail πŸ’….

So the aim of this spec is to define common error formats for the applications that need one πŸŽ€. That way they don't have to define their own, or worse, get tempted to redefine what existing HTTP status codes mean 😭. Even if an application chooses not to use it for errors, looking at its design can still help guide error-format decisions in an existing format 🧚.

2. Requirements 🌸

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119] πŸ”₯.

3. The Problem Details JSON Object πŸ’–

The canonical model for problem details is a JSON [RFC7159] object πŸ¦‹.

When it's serialized as a JSON document, that format is identified with the "application/problem+json" media type πŸŽ€.

Here's an example of an HTTP response carrying JSON problem details πŸ‘‘:

HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
Content-Language: en

{
 "type": "https://example.com/probs/out-of-credit",
 "title": "You do not have enough credit.",
 "detail": "Your current balance is 30, but that costs 50.",
 "instance": "/account/12345/msgs/abc",
 "balance": 30,
 "accounts": ["/account/12345",
              "/account/67890"]
}

Here, the out-of-credit problem (identified by its type URI) gives the reason for the 403 in "title" ✨, gives a reference for the specific occurrence of the problem with "instance" πŸ•΅οΈ, gives occurrence-specific details in "detail" 🌈, and adds two extensions πŸ“. "balance" conveys the account's balance, and "accounts" gives links where the account can be topped up πŸ’Έ.

The ability to convey problem-specific extensions lets you convey more than one problem 😭. For example:

HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
Content-Language: en

{
"type": "https://example.net/validation-error",
"title": "Your request parameters didn't validate.",
"invalid-params": [ {
                      "name": "age",
                      "reason": "must be a positive integer"
                    },
                    {
                      "name": "color",
                      "reason": "must be 'green', 'red' or 'blue'"}
                  ]
}

Note that this requires each of the subproblems to be similar enough to use the same HTTP status code πŸ™ˆ. If they aren't, the 207 (Multi-Status) [RFC4918] code could be used to encapsulate multiple status messages 🫢.

3.1. Members of a Problem Details Object πŸŽ€

A problem details object can have the following members πŸ’…:

  • "type" (string) - A URI reference [RFC3986] that identifies the problem type. This specification encourages that, when dereferenced, it provide human-readable documentation for the problem type (for example, using HTML [W3C.REC-html5-20141028]) 🌸. When this member is not present, its value is assumed to be "about:blank" 🧚.
  • "title" (string) - A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (for example, using proactive content negotiation; see [RFC7231], Section 3.4) πŸ’–.
  • "status" (number) - The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem πŸ”₯.
  • "detail" (string) - A human-readable explanation specific to this occurrence of the problem πŸ¦‹.
  • "instance" (string) - A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced 🌈.

Consumers MUST use the "type" string as the primary identifier for the problem type πŸ‘‘. The "title" string is advisory and only included for users who aren't aware of the semantics of the URI and can't discover them (for example, during offline log analysis) πŸ•΅οΈ. Consumers SHOULD NOT automatically dereference the type URI πŸ™….

The "status" member, if present, is only advisory πŸ’…. It conveys the HTTP status code used for the convenience of the consumer. Generators MUST use the same status code in the actual HTTP response, so that generic HTTP software that doesn't understand this format still behaves correctly πŸŽ€. See Section 5 for further caveats about using it ⭐.

Consumers can use the status member to figure out the original status code the generator used, in cases where it has been changed (for example, by an intermediary or cache), and when message bodies persist without HTTP information 🌸. Generic HTTP software will still use the HTTP status code 🧚.

The "detail" member, if present, ought to focus on helping the client correct the problem, rather than giving debugging information πŸ’–.

Consumers SHOULD NOT parse the "detail" member for information 🫢. Extensions are a more suitable and less error-prone way to get that info πŸ’œ.

Note that both "type" and "instance" accept relative URIs πŸ¦‹. That means they must be resolved relative to the document's base URI, as per [RFC3986], Section 5 ✨.

3.2. Extension Members 🌈

Problem type definitions MAY extend the problem details object with additional members πŸ“.

For example, our "out of credit" problem above defines two such extensions, "balance" and "accounts", to convey additional, problem-specific information πŸ’Έ.

Clients consuming problem details MUST ignore any such extensions that they don't recognize 😭. This lets problem types evolve and include additional information in the future πŸ”₯.

Note that because extensions are effectively put into a namespace by the problem type, it's not possible to define new "standard" members without defining a new media type πŸ™ˆ.


Part 1 of 3 done, bestie πŸŽ€. Part 2 is coming up next, so stay tuned πŸ’–πŸ§š

4. Defining New Problem Types ✨

Okay so, when an HTTP API needs to send back a response saying something went wrong, it might make sense to define a brand new problem type πŸ’…

But bestie, before you do that, you need to know what problem types are actually good for, and what's better handled some other way 🧚

Problem details are not a debugging tool for the underlying implementation πŸ™ˆ They're a way to expose more detail about the HTTP interface itself. If you're designing new problem types, you have to really think hard about the Security Considerations (Section 5), especially the risk of exposing attack vectors by leaking implementation internals through error messages. Not okay, no cap πŸ’€

Likewise, truly generic problems (aka conditions that could apply to literally any resource on the Web) are usually better expressed as plain status codes. Like, a "write access disallowed" problem is probably unnecessary, since a 403 Forbidden status code in response to a PUT request is already self-explanatory πŸ“

Finally, an application might already have a better way to carry an error in a format it already defines. Problem details are meant to avoid the need to invent new "fault" or "error" document formats, not to replace existing domain-specific formats 🫢

That said, you can totally add support for problem details to an existing HTTP API using HTTP content negotiation (e.g., using the Accept request header to say you'd prefer this format; see [RFC7231], Section 5.3.2) 🌸

New problem type definitions MUST document:

  1. a type URI (typically, with the http or https scheme),
  2. a title that appropriately describes it (think short), and
  3. the HTTP status code for it to be used with.

Problem type definitions MAY specify the use of the Retry-After response header ([RFC7231], Section 7.1.3) in appropriate circumstances πŸ¦‹

A problem's type URI SHOULD resolve to HTML [W3C.REC-html5-20141028] documentation that explains how to resolve the problem πŸ“š

A problem type definition MAY specify additional members on the problem details object. For example, an extension might use typed links [RFC5988] to another resource that can be used by machines to resolve the problem ✨

If such additional members are defined, their names SHOULD start with a letter (ALPHA, as per [RFC5234], Appendix B.1) and SHOULD consist of characters from ALPHA, DIGIT ([RFC5234], Appendix B.1), and "_" (so that it can be serialized in formats other than JSON), and they SHOULD be three characters or longer. The vibe is clean, consistent names that work everywhere πŸ’œ


4.1. Example

Let's say you're publishing an HTTP API for your online shopping cart. You might need to indicate that the user is out of credit (our example from above), and therefore cannot make the purchase πŸ›’

If you already have an application-specific format that can hold this information, it's probably best to just use that. But if you don't, you might consider using one of the problem details formats: JSON if your API is JSON-based, or XML if it uses that format πŸŽ€

To do so, look for an already-defined type URI that suits your purposes. If one is available, you can reuse it πŸ”

If one isn't available, you could mint and document a new type URI (which ought to be under your control and stable over time), plus an appropriate title and the HTTP status code it will be used with, along with what it means and how it should be handled 🧁

In summary: an instance URI will always identify a specific occurrence of a problem. On the other hand, type URIs can be reused if an appropriate description of a problem type is already available someplace else, or they can be created for new problem types. Main character energy for URIs, honestly πŸ‘‘


4.2. Predefined Problem Types

This specification reserves the use of one URI as a problem type:

The "about:blank" URI [RFC6694], when used as a problem type, indicates that the problem has no additional semantics beyond that of the HTTP status code. Just the status code, nothing extra 🀍

When "about:blank" is used, the title SHOULD be the same as the recommended HTTP status phrase for that code (e.g., "Not Found" for 404, and so on), although it MAY be localized to suit client preferences (expressed with the Accept-Language request header) 🌍

Please note that according to how the "type" member is defined (Section 3.1), the "about:blank" URI is the default value for that member. Consequently, any problem details object not carrying an explicit "type" member implicitly uses this URI 🫧


5. Security Considerations πŸ”

Okay, this section is serious, so listen up 🚨

When defining a new problem type, the information included must be carefully vetted. Likewise, when actually generating a problem (however it is serialized), the details given must also be scrutinized πŸ•΅οΈβ€β™€οΈ

Risks include leaking information that can be exploited to compromise the system, access to the system, or the privacy of users of the system. That's a lot of danger, bestie 😭

Generators providing links to occurrence information are encouraged to avoid making implementation details such as a stack dump available through the HTTP interface, since this can expose sensitive details of the server implementation, its data, and so on. No stack dumps on the public internet, please πŸ™…β€β™€οΈ

The "status" member duplicates the information available in the HTTP status code itself, thereby bringing the possibility of disagreement between the two. Their relative precedence is not clear, since a disagreement might indicate that (for example) an intermediary has modified the HTTP status code in transit (e.g., by a proxy or cache). Two sources of truth is giving chaos πŸŒ€

As such, those defining problem types as well as generators and consumers of problems need to be aware that generic software (such as proxies, load balancers, firewalls, and virus scanners) is unlikely to know of or respect the status code conveyed in this member. So double-check, periodt πŸ’€


6. IANA Considerations 🌈

This specification defines two new Internet media types [RFC6838]. Two new media types, very exciting πŸŽ‰

6.1. application/problem+json

Here's the registration template for the JSON one, copied exactly as written:

   Type name:  application

   Subtype name:  problem+json

   Required parameters:  None

   Optional parameters:  None; unrecognized parameters should be ignored

   Encoding considerations:  Same as [RFC7159]

   Security considerations:  see Section 5 of this document

   Interoperability considerations:  None

   Published specification:  RFC 7807 (this document)

   Applications that use this media type:  HTTP

   Fragment identifier considerations:  Same as for application/json
      ([RFC7159])

   Additional information:

      Deprecated alias names for this type:  n/a

      Magic number(s):  n/a

      File extension(s):  n/a

      Macintosh file type code(s):  n/a

   Person and email address to contact for further information:
      Mark Nottingham <mnot@mnot.net>

   Intended usage:  COMMON

   Restrictions on usage:  None.

   Author:  Mark Nottingham <mnot@mnot.net>

   Change controller:  IESG

6.2. application/problem+xml

And here's the one for XML, also verbatim 🧾

   Type name:  application

   Subtype name:  problem+xml

   Required parameters:  None

   Optional parameters:  None; unrecognized parameters should be ignored

   Encoding considerations:  Same as [RFC7303]

   Security considerations:  see Section 5 of this document

   Interoperability considerations:  None

   Published specification:  RFC 7807 (this document)

   Applications that use this media type:  HTTP

   Fragment identifier considerations:  Same as for application/xml (as
      specified by Section 5 of [RFC7303])

   Additional information:

      Deprecated alias names for this type:  n/a

      Magic number(s):  n/a

      File extension(s):  n/a

      Macintosh file type code(s):  n/a

   Person and email address to contact for further information:
      Mark Nottingham <mnot@mnot.net>

   Intended usage:  COMMON

   Restrictions on usage:  None.

   Author:  Mark Nottingham <mnot@mnot.net>

   Change controller:  IESG

7. References πŸ“–

Every single reference, with all its details, so nothing gets lost 🫢

7.1. Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119,
              DOI 10.17487/RFC2119, March 1997,
              <http://www.rfc-editor.org/info/rfc2119>.

   [RFC3986]  Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
              Resource Identifier (URI): Generic Syntax", STD 66,
              RFC 3986, DOI 10.17487/RFC3986, January 2005,
              <http://www.rfc-editor.org/info/rfc3986>.

   [RFC5234]  Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax
              Specifications: ABNF", STD 68, RFC 5234,
              DOI 10.17487/RFC5234, January 2008,
              <http://www.rfc-editor.org/info/rfc5234>.

   [RFC7159]  Bray, T., Ed., "The JavaScript Object Notation (JSON) Data
              Interchange Format", RFC 7159, DOI 10.17487/RFC7159, March
              2014, <http://www.rfc-editor.org/info/rfc7159>.

   [RFC7230]  Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer
              Protocol (HTTP/1.1): Message Syntax and Routing",
              RFC 7230, DOI 10.17487/RFC7230, June 2014,
              <http://www.rfc-editor.org/info/rfc7230>.

   [RFC7231]  Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer
              Protocol (HTTP/1.1): Semantics and Content", RFC 7231,
              DOI 10.17487/RFC7231, June 2014,
              <http://www.rfc-editor.org/info/rfc7231>.

   [W3C.REC-xml-20081126]
              Bray, T., Paoli, J., Sperberg-McQueen, M., Maler, E., and
              F. Yergeau, "Extensible Markup Language (XML) 1.0 (Fifth
              Edition)", W3C Recommendation REC-xml-20081126, November
              2008, <http://www.w3.org/TR/2008/REC-xml-20081126>.

7.2. Informative References

   [ISO-19757-2]
              International Organization for Standardization,
              "Information Technology --- Document Schema Definition
              Languages (DSDL) --- Part 2: Grammar-based Validation ---
              RELAX NG", ISO/IEC 19757-2, 2003.

   [RFC4918]  Dusseault, L., Ed., "HTTP Extensions for Web Distributed
              Authoring and Versioning (WebDAV)", RFC 4918,
              DOI 10.17487/RFC4918, June 2007,
              <http://www.rfc-editor.org/info/rfc4918>.

   [RFC5988]  Nottingham, M., "Web Linking", RFC 5988,
              DOI 10.17487/RFC5988, October 2010,
              <http://www.rfc-editor.org/info/rfc5988>.

   [RFC6694]  Moonesamy, S., Ed., "The "about" URI Scheme", RFC 6694,
              DOI 10.17487/RFC6694, August 2012,
              <http://www.rfc-editor.org/info/rfc6694>.

   [RFC6838]  Freed, N., Klensin, J., and T. Hansen, "Media Type
              Specifications and Registration Procedures", BCP 13,
              RFC 6838, DOI 10.17487/RFC6838, January 2013,
              <http://www.rfc-editor.org/info/rfc6838>.

   [RFC7303]  Thompson, H. and C. Lilley, "XML Media Types", RFC 7303,
              DOI 10.17487/RFC7303, July 2014,
              <http://www.rfc-editor.org/info/rfc7303>.

   [W3C.REC-html5-20141028]
              Hickson, I., Berjon, R., Faulkner, S., Leithead, T.,
              Navara, E., O'Connor, E., and S. Pfeiffer, "HTML5", W3C
              Recommendation REC-html5-20141028, October 2014,
              <http://www.w3.org/TR/2014/REC-html5-20141028>.

   [W3C.REC-rdfa-core-20130822]
              Adida, B., Birbeck, M., McCarron, S., and I. Herman, "RDFa
              Core 1.1 - Second Edition", W3C Recommendation
              REC-rdfa-core-20130822, August 2013,
              <http://www.w3.org/TR/2013/REC-rdfa-core-20130822>.

   [W3C.REC-xml-stylesheet-20101028]
              Clark, J., Pieters, S., and H. Thompson, "Associating
              Style Sheets with XML documents 1.0 (Second Edition)", W3C
              Recommendation REC-xml-stylesheet-20101028, October 2010,
              <http://www.w3.org/TR/2010/REC-xml-stylesheet-20101028>.

Appendix A. HTTP Problems and XML ✨

okay so some HTTP-based APIs are full XML girlies πŸ’… and use it as their main format. Those APIs can express problem details using the format in this appendix πŸŽ€

The RELAX NG schema [ISO-19757-2] for the XML format is below. Bestie, heads up: this schema is only documentation πŸ“. It is not a normative schema that captures every constraint of the XML format. It would also be possible to use other XML schema languages to define a similar set of constraints, depending on what features the chosen schema language has πŸ¦‹

   default namespace ns = "urn:ietf:rfc:7807"

   start = problem

   problem =
     element problem {
       (  element  type            { xsd:anyURI }?
        & element  title           { xsd:string }?
        & element  detail          { xsd:string }?
        & element  status          { xsd:positiveInteger }?
        & element  instance        { xsd:anyURI }? ),
       anyNsElement
     }

   anyNsElement =
     (  element    ns:*  { anyNsElement | text }
      | attribute  *     { text })*

The media type for this format is "application/problem+xml" πŸ’œ

Extension arrays and objects get turned into the XML format like this: an element with a child or children counts as an object, except when the element only contains child elements named i. Those count as arrays 🌸 For example, the example above shows up in XML like so:

HTTP/1.1 403 Forbidden
Content-Type: application/problem+xml
Content-Language: en

<?xml version="1.0" encoding="UTF-8"?>
<problem xmlns="urn:ietf:rfc:7807">
  <type>https://example.com/probs/out-of-credit</type>
  <title>You do not have enough credit.</title>
  <detail>Your current balance is 30, but that costs 50.</detail>
  <instance>https://example.net/account/12345/msgs/abc</instance>
  <balance>30</balance>
  <accounts>
    <i>https://example.net/account/12345</i>
    <i>https://example.net/account/67890</i>
  </accounts>
</problem>

Okay, the namespace part is important πŸ‘€ This format uses an XML namespace, mainly so it can get embedded into other XML-based formats. It does NOT mean you can or should add elements or attributes from other namespaces. The RELAX NG schema only allows elements from the one namespace used in the format. Any extension arrays and objects MUST be serialized into XML markup using only that namespace ⚠️

When you're using the XML format, you can embed an XML processing instruction that tells clients to transform the XML using the referenced XSLT code [W3C.REC-xml-stylesheet-20101028]. If that code transforms the XML into (X)HTML, then you can serve the XML format and still have clients that can do the transformation show a human-friendly (X)HTML page that gets rendered and displayed on the client 🌈 Just a tip from the spec: it's advisable to use XSLT 1.0 so that as many clients as possible can run your XSLT code 🧚


Appendix B. Using Problem Details with Other Formats

Sometimes it's a win to embed problem details in formats other than the ones described here πŸ¦‹ For example, an API that uses HTML [W3C.REC-html5-20141028] might want to express its problem details in HTML too πŸ’–

You can embed problem details in other formats in one of two ways: by wrapping one of the existing serializations (JSON or XML) inside that format, or by translating the model of a problem detail (as specified in Section 3) into the format's own conventions πŸŽ€

For example, in HTML you could embed a problem by wrapping JSON in a script tag:

       <script type="application/problem+json">
         {
          "type": "https://example.com/probs/out-of-credit",
          "title": "You do not have enough credit.",
          "detail": "Your current balance is 30, but that costs 50.",
          "instance": "/account/12345/msgs/abc",
          "balance": 30,
          "accounts": ["/account/12345",
                       "/account/67890"]
         }
       </script>

or by inventing a mapping into RDFa [W3C.REC-rdfa-core-20130822].

This specification does not make specific recommendations about embedding problem details in other formats. The right way to do it depends on both the format being used and how that format is applied 🫢


Acknowledgements

Huge thanks to Jan Algermissen, Subbu Allamaraju, Mike Amundsen, Roy Fielding, Eran Hammer, Sam Johnston, Mike McCall, Julian Reschke, and James Snell for reviewing this specification πŸ™ˆπŸ’œ

Authors' Addresses ✨

Mark Nottingham Akamai

Email: mnot@mnot.net URI: https://www.mnot.net/

Erik Wilde

Email: erik.wilde@dret.net URI: http://dret.net/netdret/

πŸ“¦ where this page comes from