Skip to content

Improvements for Problem guideline #826

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
215 changes: 180 additions & 35 deletions chapters/http-status-codes-and-errors.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -564,52 +564,74 @@ number of requests made within a given window for each named entity.
== {MUST} support problem JSON

{RFC-9457}[RFC 9457] defines a Problem JSON object using the media type
`application/problem+json` to provide an extensible human and machine readable
failure information beyond the HTTP response status code to transports the
failure kind (`type` / `title`) and the failure cause and location (`instant` /
`detail`). To make best use of this additional failure information, every
endpoints must be capable of returning a Problem JSON on client usage errors
({4xx} status codes) as well as server side processing errors ({5xx} status
codes).

*Note:* Clients must be robust and *not rely* on a Problem JSON object
being returned, since (a) failure responses may be created by infrastructure
components not aware of this guideline or (b) service may be unable to comply
with this guideline in certain error situations.
`application/problem+json` to provide a standardized format for expressing
errors in API responses. It serves several purposes:

*Hint:* The media type `application/problem+json` is often not implemented as
a subset of `application/json` by libraries and services! Thus clients need to
include `application/problem+json` in the {Accept}-Header to trigger delivery
of the extended failure information.
* Developers: to debug, diagnose and resolve issues during API integration or
operation
* Client applications: to inform users about errors (in user interface) and to
support automated processing and error handling when appropriate.

The OpenAPI schema definition of the Problem JSON object can be found
https://opensource.zalando.com/restful-api-guidelines/models/problem-1.0.1.yaml[on
GitHub]. You can reference it by using:
==== Problem schema members, suppported by the API guidelines
Problem detail objects can have the following members.

[source,yaml]
----
responses:
503:
description: Service Unavailable
content:
"application/problem+json":
schema:
$ref: 'https://opensource.zalando.com/restful-api-guidelines/models/problem-1.0.1.yaml#/Problem'
----
**Note:** If a member's value type does not match the specified type,
the member MUST be ignored -- i.e., processing will continue as if
the member had not been present.

===== status (integer)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should avoid specification of the problem object in the GUI guideline redundantly (and possibly inconsistently) to the open-source specification in https://opensource.zalando.com/restful-api-guidelines/models/problem-1.0.1.yaml

Instead we should clearly refer to it and update it as part of the PR, if helpful.
It also allows us to better understand the differences.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that we should avoid redundancies, but having it written out in the guidelines makes it easier to read than just pointing to the file. Not sure what the best way of doing this is, though.

The HTTP status code generated by the origin server for occurrences of the problem.
Example:

`"status": 400`

===== 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.
Example:

`"title": "Invalid parameter"`

===== detail (string)
A human-readable explanation specific to this occurrence of the problem.
Provides additional context or specifics about the error for debugging
or display to the user.
Example:

You may define custom problem types as extensions of the Problem JSON object
if your API needs to return specific, additional, and more detailed error
information.
`"detail": "The 'color' parameter is invalid"`

*Note:* Problem `type` and `instance` identifiers in our APIs are not meant
to be resolved. {RFC-9457}[RFC 9457] encourages that problem types are URI
===== type and instance (URI references)
The standardized Problem JSON object also allows for the following optional
members:

- type: a URI identifying the problem type, typically more specific than the
HTTP status code. In many cases, an error code can be placed in the type
property. It may support automated client decisions in certain failure modes.
If the `type` doesn’t provide additional information, it can be omitted
(defaulting to `"about:blank"`).
- instance: a URI reference that identifies specific occurrence of the problem.
This field should serve the purpose of defining a clear error instance from
which the developer can determine the source location of the error.
Additionally, it may include relevant contextual information, such as parameters
associated with the error and optionally `Flow-ID` for debugging purposes.

Examples:

`"type": "https://example.com/errors/invalid-parameter"`

`"type": "https://example.com/errors/ERR12345" (with error code)`

`"instance": "/errors/12345"`

*Note:* {RFC-9457}[RFC 9457] encourages that problem types are URI
references that point to human-readable documentation, *but* we deliberately
decided against that, as all important parts of the API must be documented
using <<101, OpenAPI>> anyway. In addition, URLs tend to be fragile and not
very stable over longer periods because of organizational and documentation
changes and descriptions might easily get out of sync.

In order to stay compatible with {RFC-9457}[RFC 9457] we proposed to use
In order to stay compatible with {RFC-9457}[RFC 9457] we recommend to use
https://tools.ietf.org/html/rfc3986#section-4.1[relative URI references]
usually defined by `absolute-path [ '?' query ] [ '#' fragment ]` as simplified
identifiers in `type` and `instance` fields:
Expand All @@ -625,6 +647,129 @@ please reference
https://opensource.zalando.com/restful-api-guidelines/models/problem-1.0.0.yaml#/Problem[problem-1.0.0.yaml#/Problem]
instead.

==== Usage of Problem Object
Clients may utilize properties in the Problem Object, particularly those
documented in the API specification. However, they *should not* depend on these
properties being present or having specific values.
The examples of such cases are:

- response might be created by infrastructure components (and have a different
response format, comparing to the guidelines)
- response might be created by a service that is unable to comply with the
guidelines due to certain error situations

In cases where the Problem Object lacks the required information, clients must
implement fallback mechanisms, defaulting to reasonable behavior similar to
handling errors without a Problem Object provided.

The OpenAPI schema definition of the Problem JSON object can be found
https://opensource.zalando.com/restful-api-guidelines/models/problem-1.0.1.yaml[on
GitHub]. You can reference it by using:

[source,yaml]
----
responses:
503:
description: Service Unavailable
content:
"application/problem+json":
schema:
$ref: 'https://opensource.zalando.com/restful-api-guidelines/models/problem-1.0.1.yaml#/Problem'
----

*Hint:* The media type `application/problem+json` is often not implemented as
a subset of `application/json` by libraries and services, thus clients need to
include `application/problem+json` in the {Accept}-Header to trigger delivery
of the extended failure information.

==== Automated processing of Problem Object on client side
Problem details are often not described explicitly in the API and may evolve
over time.

Unless the API defines and enumerates stable values for `type` and `instance`
with clear semantics, these fields *should not* be relied upon for client-side
automated decisions.

The following guidelines offer best practices for utilizing type in automated
processing:

1. Property `type` may be used by clients to make automatic decisions in
certain failure modes. The `title` property serves as a concise,
human-readable summary of the type. It is particularly helpful for debugging
and serves as an engineer-readable shorthand for the problem type.

2. Clients may use these fields to drive automated actions if the API
explicitly defines the semantics of `type` and `instance` and enumerates
stable values. This can be achieved by extending the Problem JSON object and
associating an x-extensible-enum with the type property.

3. Clients must handle scenarios where the type is absent or unrecognized and
fallback to default behaviors.

4. For collections of related APIs, using shared type values for similar errors
and distinct values for different errors simplifies automated processing and
error handling for clients working across APIs.

*Note:* Include descriptions for each known error that can happen directly in
the specification or reference external documentation to clarify their meanings
and intended use.

==== Extensions of Problem Object schema
APIs can define custom fields in the Problem Object to provide more context
to meet specific application needs.
The custom fields should not conflict with the standard fields.
To extend the Problem Object, the API specification must define the custom
Problem, which would include Problem object members and custom ones. The
custom Problem can be used in the API specification as a reference, same as
a standard Problem object.
Example:
[source,yaml]
----
components:
schemas:
Problem:
type: object
properties:
type:
type: string
format: uri
example: "https://example.com/errors/invalid-parameter"
title:
type: string
example: "Invalid Request Parameter"
status:
type: integer
example: 400
detail:
type: string
example: "The 'color' parameter is invalid"

CustomProblem:
allOf:
- $ref: "#/components/schemas/Problem"
properties:
errorCode:
type: string
example: "ERROR12345"
flowId:
type: string
example: "2914eefe-814e-4100-a332-42bac3352524"
----

*Note:* In case when client does not support some of the fields,
they should be ignored.

==== Handling Multiple Errors in Batch/Bulk Responses
When an API processes batch requests, multiple errors may occur.
To ensure clarity and usability, the response should structure these errors
in a way that allows clients to identify and handle individual failures.

Depending on the use-case the response can be structured in two ways:

- as an array of Problem objects where each entry in the array represents an
individual error related to a specific request item.
- as a map where associated value contains the corresponding Problem object for
that specific request item.

[#177]
== {MUST} not expose stack traces
Expand Down