Skip to content

Commit

Permalink
chore(guidelines): Relate to rfc9457 instead of rfc7807 (#80)
Browse files Browse the repository at this point in the history
RFC7807 has been replaced by RFC9457.

Changelog:

### Update

- Referred to RFC 9457 instead of obsoleted RFC 7807 in "MUST use
problem+json as error response format
[R000034](https://api.otto.de/portal/guidelines/r000034)", "SHOULD use
existing problem types
[R000037](http://api.otto.de/portal/guidelines/r000037)", and "MAY add
custom extensions by defining a problem type
[R000040](https://api.otto.de/portal/guidelines/r000040)".

---------

Co-authored-by: Stefan Schmidt <[email protected]>
Co-authored-by: maxedenharter0507 <[email protected]>
  • Loading branch information
3 people authored Feb 12, 2025
1 parent 49fbf29 commit 62992c8
Show file tree
Hide file tree
Showing 7 changed files with 17 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ id: R000040

# MAY add custom extensions by defining a problem `type`

As described in [section 3.2](https://www.rfc-editor.org/rfc/rfc7807#section-3.2) of [RFC 7807](https://www.rfc-editor.org/rfc/rfc7807) _problem `type` definitions may extend the problem details object with additional members_.
As described in [section 3.2](https://www.rfc-editor.org/rfc/rfc9457#section-3.2) of [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) _problem `type` definitions may extend the problem details object with additional members_.
Thus, API providers need to define a specific problem `type` if they want to add additional non-standard properties to a problem+json response.

In general, clients must ignore any extension they do not recognize.
This allows problem types to evolve and include additional information in the future.

Before defining a new problem type, check if the type is really required and cannot be expressed just by using the HTTP status code.
For example communicating to the client that he is not allowed to place an order can easily be expressed by the generic HTTP status code [403 Forbidden](https://www.rfc-editor.org/rfc/rfc9110#name-403-forbidden).
If this is the case, just use the problem type [`about:blank`](https://www.rfc-editor.org/rfc/rfc7807#section-4.2) that signals that the problem is semantically identical to the meaning of the status code.
If this is the case, just use the problem type [`about:blank`](https://www.rfc-editor.org/rfc/rfc9457#section-4.2.1) that signals that the problem is semantically identical to the meaning of the status code.

Creating a new `type` always includes having a fixed human-readable `title` and a fixed `status` associated (see [https://www.rfc-editor.org/rfc/rfc7807#section-4](https://www.rfc-editor.org/rfc/rfc7807#section-4)).
Creating a new `type` always includes having a fixed human-readable `title` and a fixed `status` associated (see [https://www.rfc-editor.org/rfc/rfc9457#section-4](https://www.rfc-editor.org/rfc/rfc9457#section-4)).

The URI encoded in `type` must be treated as an identifier that should not change. While encouraged, it does not need to be resolvable.
The `type` URI should be in the same URL namespace as the APIs endpoints. If all API endpoints are located under `https://api.otto.de/payment/` the custom `type` URLs should als be located under the same context path (e.g., `https://api.otto.de/payment/problems/credit-too-low`).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ id: R000034

# MUST use `problem+json` as error response format

We decided to adopt "Problem Details for HTTP APIs" as described in [RFC 7807](https://tools.ietf.org/html/rfc7807).
We decided to adopt "Problem Details for HTTP APIs" as described in [RFC 9457](https://tools.ietf.org/html/rfc9457).
In case of an error, all REST operations must return an error response in this well-defined format along with the appropriate media type `application/problem+json`. This error response enhances the correctly used [HTTP status code](../../../http/status-codes/rules/must-use-standard-http-status-codes.md) with contextual information.

Example response:
Expand All @@ -26,7 +26,7 @@ Content-Type: application/problem+json
Always respond with the corresponding media type `application/problem+json` regardless of the given `accept` header.
:::

The [`type`](https://www.rfc-editor.org/rfc/rfc7807#section-3.1) of the problem object should be used to identify the problem type globally.
The [`type`](https://www.rfc-editor.org/rfc/rfc9457#section-3.1.1) of the problem object should be used to identify the problem type globally.
The URI does not need to be resolvable. If it is resolvable, it should contain a human-readable description of the problem type.

Responses should [use existing error types](./should-use-existing-problem-types.md) if possible to keep error churn as low as possible.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ id: R000037

# SHOULD use existing problem types

In addition to the [predefined types](https://www.rfc-editor.org/rfc/rfc7807#section-4.2) in RFC7807, we have defined
In addition to the [predefined types](https://www.rfc-editor.org/rfc/rfc9457#section-4.2) in RFC9457, we have defined
the problem type [https://api.otto.de/portal/problems/validation-failed](./must-use-extension-for-input-validation-errors.md).

We encourage API designers to reuse existing problem types instead of creating completely new or slightly modified ones.
Expand Down
4 changes: 2 additions & 2 deletions dev-context/rest/error-responses.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Content-Type: application/problem+json
### validation-failed problem type

As the `problem+json` media type standard does not provide a problem type for failed input validation, we had to establish one.
One could argue that the "about:blank" problem type could be used in combination with the already defined `details` property. But [RFC 7807](https://tools.ietf.org/html/rfc7807) explicitly states, that this property is not meant to be parsed.
One could argue that the "about:blank" problem type could be used in combination with the already defined `details` property. But [RFC 9457](https://tools.ietf.org/html/rfc9457) explicitly states, that this property is not meant to be parsed.
Therefore, we created a new type `https://api.otto.de/portal/problems/validation-failed` with a custom property called `validationErrors`.

### Notes / Questions
Expand All @@ -55,7 +55,7 @@ Therefore, we created a new type `https://api.otto.de/portal/problems/validation

- [HTTP Status Codes](https://httpstatuses.com)
- [Blog: Indicating Problems in HTTP APIs](https://www.mnot.net/blog/2013/05/15/http_problem)
- [IETF RFC: Problem Details for HTTP APIs](https://tools.ietf.org/html/rfc7807)
- [IETF RFC: Problem Details for HTTP APIs](https://tools.ietf.org/html/rfc9457)
- [Registered IANA Media Type](https://www.iana.org/assignments/media-types/application/problem+json)
- [problem+json JAVA](https://github.com/zalando/problem)
- [problem+json for Spring MVC](https://github.com/zalando/problem-spring-web)
Expand Down
8 changes: 4 additions & 4 deletions src/linting/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { UseKebabCaseForPathParameter } from "./rules/use-kebab-case-for-path-pa
import { UseKebabCaseInUri } from "./rules/use-kebab-case-in-uri.js";
import { UseOas3 } from "./rules/use-oas-3.js";
import { UseStringEnum } from "./rules/use-string-enum.js";
import { Operation4xxProblemDetailsRfc7807 } from "./rules/operation-4xx-problem-details-rfc7807.js";
import { Operation4xxProblemDetailsRfc9457 } from "./rules/operation-4xx-problem-details-rfc9457.js";

export const id: Plugin["id"] = "api-guidelines";

Expand Down Expand Up @@ -47,7 +47,7 @@ export const rules = {
"use-kebab-case-in-uri": UseKebabCaseInUri,
"use-string-enum": UseStringEnum,
"use-tls": UseTLS,
"operation-4xx-problem-details-rfc7807": Operation4xxProblemDetailsRfc7807,
"operation-4xx-problem-details-rfc9457": Operation4xxProblemDetailsRfc9457,
},
};

Expand All @@ -56,8 +56,8 @@ export const configs = {
rules: {
"info-contact": "error", // https://api.otto.de/portal/guidelines/r000078
"operation-2xx-response": "error", // https://api.otto.de/portal/guidelines/r000011
// "operation-4xx-problem-details-rfc7807": "error", // https://api.otto.de/portal/guidelines/r000034
"api-guidelines/operation-4xx-problem-details-rfc7807": "error", // https://api.otto.de/portal/guidelines/r000034
// "operation-4xx-problem-details-rfc9457": "error", // https://api.otto.de/portal/guidelines/r000034
"api-guidelines/operation-4xx-problem-details-rfc9457": "error", // https://api.otto.de/portal/guidelines/r000034
"no-path-trailing-slash": "error", // https://api.otto.de/portal/guidelines/r000020
"api-guidelines/always-return-json-object": "error", // https://api.otto.de/portal/guidelines/r004030
"api-guidelines/define-permissions-with-scope": "error", // https://api.otto.de/portal/guidelines/r000047
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { lintFromString } from "@redocly/openapi-core";
import { Operation4xxProblemDetailsRfc7807 } from "./operation-4xx-problem-details-rfc7807.js";
import { Operation4xxProblemDetailsRfc9457 } from "./operation-4xx-problem-details-rfc9457.js";
import { createTestConfig } from "./__tests__/createTestConfig.js";
import { removeClutter } from "./__tests__/removeClutter.js";

const config = createTestConfig({
oas3: {
// @ts-ignore
"test-rule": Operation4xxProblemDetailsRfc7807,
"test-rule": Operation4xxProblemDetailsRfc9457,
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
this is copied from
https://github.com/Redocly/redocly-cli/blob/main/packages/core/src/rules/oas3/operation-4xx-problem-details-rfc7807.ts
https://github.com/Redocly/redocly-cli/blob/main/packages/core/src/rules/oas3/operation-4xx-problem-details-rfc9457.ts
and modified to ignore anyOf, allOf, oneOf
Expand All @@ -13,9 +13,9 @@ import type { Oas3Rule } from "@redocly/openapi-core/lib/visitors.d.js";
import { validateDefinedAndNonEmpty } from "@redocly/openapi-core/lib/rules/utils";

/**
* Validation according rfc7807 - https://datatracker.ietf.org/doc/html/rfc7807
* Validation according rfc9457 - https://datatracker.ietf.org/doc/html/rfc9457
*/
export const Operation4xxProblemDetailsRfc7807: Oas3Rule = () => {
export const Operation4xxProblemDetailsRfc9457: Oas3Rule = () => {
return {
Response: {
skip(_response, key: string | number) {
Expand Down

0 comments on commit 62992c8

Please sign in to comment.