Skip to content

Add support for resource inheritance in OpenAPI #1704

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

Merged
merged 4 commits into from
Mar 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions docs/docfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"files": [
"api/**.yml",
"api/index.md",
"ext/openapi/index.md",
"getting-started/**.md",
"getting-started/**/toc.yml",
"usage/**.md",
Expand Down
127 changes: 127 additions & 0 deletions docs/ext/openapi/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# JSON:API Extension for OpenAPI

This extension facilitates using OpenAPI client generators targeting JSON:API documents.

In JSON:API, a resource object contains the `type` member, which defines the structure of nested [attributes](https://jsonapi.org/format/#document-resource-object-attributes) and [relationships](https://jsonapi.org/format/#document-resource-object-relationships) objects.
While OpenAPI supports such constraints using `allOf` inheritance with a discriminator property for the `data` member,
it provides no way to express that the discriminator recursively applies to nested objects.

This extension addresses that limitation by defining additional discriminator properties to guide code generation tools.

## URI

This extension has the URI `https://www.jsonapi.net/ext/openapi`.
Because code generators often choke on the double quotes in `Accept` and `Content-Type` HTTP header values, a relaxed form is also permitted: `openapi`.

For example, the following `Content-Type` header:

```http
Content-Type: application/vnd.api+json; ext="https://www.jsonapi.net/ext/openapi"
```

is equivalent to:

```http
Content-Type: application/vnd.api+json; ext=openapi
```

To avoid the need for double quotes when multiple extensions are used, the following relaxed form can be used:

```http
Content-Type: application/vnd.api+json; ext=openapi; ext=atomic
```

> [!NOTE]
> The [base specification](https://jsonapi.org/format/#media-type-parameter-rules) *forbids* the use of multiple `ext` parameters
> and *requires* that each extension name must be a URI.
> This extension relaxes both constraints for practical reasons, to workaround bugs in client generators that produce broken code otherwise.

## Namespace

This extension uses the namespace `openapi`.

> [!NOTE]
> JSON:API extensions can only introduce new document members using a reserved namespace as a prefix.

## Document Structure

A document that supports this extension MAY include any of the top-level members allowed by the base specification,
including any members defined in the [Atomic Operations extension](https://jsonapi.org/ext/atomic/).

### Resource Objects

In addition to the members allowed by the base specification, the following member MAY be included
in [attributes](https://jsonapi.org/format/#document-resource-object-attributes) and [relationships](https://jsonapi.org/format/#document-resource-object-relationships) objects:

* `openapi:discriminator` - A string that MUST be identical to the `type` member in the containing [resource object](https://jsonapi.org/format/#document-resource-objects).

Here's how an article (i.e. a resource of type "articles") might appear in a document:

```json
{
"data": {
"type": "articles",
"id": "1",
"attributes": {
"openapi:discriminator": "articles",
"title": "Rails is Omakase"
},
"relationships": {
"openapi:discriminator": "articles",
"author": {
"data": { "type": "people", "id": "9" }
}
}
}
}
```

### Atomic Operations

In addition to the members allowed by the [Atomic Operations extension](https://jsonapi.org/ext/atomic/),
the following member MAY be included in elements of an `atomic:operations` array:

* `openapi:discriminator` - A free-format string to facilitate generation of client code.

For example:

```http
POST /operations HTTP/1.1
Host: example.org
Content-Type: application/vnd.api+json; ext="https://www.jsonapi.net/ext/openapi https://jsonapi.org/ext/atomic"
Accept: application/vnd.api+json; ext="https://www.jsonapi.net/ext/openapi https://jsonapi.org/ext/atomic"

{
"atomic:operations": [{
"openapi:discriminator": "add-article",
"op": "add",
"data": {
"type": "articles",
"attributes": {
"openapi:discriminator": "articles",
"title": "JSON API paints my bikeshed!"
}
}
}]
}
```

## Processing

A server MAY ignore the `openapi:discriminator` member in [attributes](https://jsonapi.org/format/#document-resource-object-attributes) and [relationships](https://jsonapi.org/format/#document-resource-object-relationships) objects from incoming requests.
A server SHOULD ignore the `openapi:discriminator` member in elements of an `atomic:operations` array.

A server MUST include the `openapi:discriminator` member in [attributes](https://jsonapi.org/format/#document-resource-object-attributes) and [relationships](https://jsonapi.org/format/#document-resource-object-relationships) objects in outgoing responses.
The member value MUST be the same as the `type` member value of the containing resource object.

A client MAY include the `openapi:discriminator` member in [attributes](https://jsonapi.org/format/#document-resource-object-attributes) and [relationships](https://jsonapi.org/format/#document-resource-object-relationships) objects in outgoing requests.
The member value MUST be the same as the `type` member value of the containing resource object.

A client MAY include the `openapi:discriminator` member in elements of an `atomic:operations` array.

### Processing Errors

A server SHOULD validate that the value of the `openapi:discriminator` member in
[attributes](https://jsonapi.org/format/#document-resource-object-attributes) and [relationships](https://jsonapi.org/format/#document-resource-object-relationships) objects
is identical to the `type` member in the containing resource object. When validation fails, the server MUST respond with a `409 Conflict`
and SHOULD include a document with a top-level `errors` member that contains an error object.
Loading
Loading