|
| 1 | +# JSON:API Extension for OpenAPI |
| 2 | + |
| 3 | +This extension facilitates using OpenAPI client generators targeting JSON:API documents. |
| 4 | + |
| 5 | +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. |
| 6 | +While OpenAPI supports such constraints using `allOf` inheritance with a discriminator property for the `data` member, |
| 7 | +it provides no way to express that the discriminator recursively applies to nested objects. |
| 8 | + |
| 9 | +This extension addresses that limitation by defining additional discriminator properties to guide code generation tools. |
| 10 | + |
| 11 | +## URI |
| 12 | + |
| 13 | +This extension has the URI `https://www.jsonapi.net/ext/openapi`. |
| 14 | +Because code generators often choke on the double quotes in `Accept` and `Content-Type` HTTP header values, a relaxed form is also permitted: `openapi`. |
| 15 | + |
| 16 | +For example, the following `Content-Type` header: |
| 17 | + |
| 18 | +```http |
| 19 | +Content-Type: application/vnd.api+json; ext="https://www.jsonapi.net/ext/openapi" |
| 20 | +``` |
| 21 | + |
| 22 | +is equivalent to: |
| 23 | + |
| 24 | +```http |
| 25 | +Content-Type: application/vnd.api+json; ext=openapi |
| 26 | +``` |
| 27 | + |
| 28 | +To avoid the need for double quotes when multiple extensions are used, the following relaxed form can be used: |
| 29 | + |
| 30 | +```http |
| 31 | +Content-Type: application/vnd.api+json; ext=openapi; ext=atomic |
| 32 | +``` |
| 33 | + |
| 34 | +> [!NOTE] |
| 35 | +> The [base specification](https://jsonapi.org/format/#media-type-parameter-rules) *forbids* the use of multiple `ext` parameters |
| 36 | +> and *requires* that each extension name must be a URI. |
| 37 | +> This extension relaxes both constraints for practical reasons, to workaround bugs in client generators that produce broken code otherwise. |
| 38 | +
|
| 39 | +## Namespace |
| 40 | + |
| 41 | +This extension uses the namespace `openapi`. |
| 42 | + |
| 43 | +> [!NOTE] |
| 44 | +> JSON:API extensions can only introduce new document members using a reserved namespace as a prefix. |
| 45 | +
|
| 46 | +## Document Structure |
| 47 | + |
| 48 | +A document that supports this extension MAY include any of the top-level members allowed by the base specification, |
| 49 | +including any members defined in the [Atomic Operations extension](https://jsonapi.org/ext/atomic/). |
| 50 | + |
| 51 | +### Resource Objects |
| 52 | + |
| 53 | +In addition to the members allowed by the base specification, the following member MAY be included |
| 54 | +in [attributes](https://jsonapi.org/format/#document-resource-object-attributes) and [relationships](https://jsonapi.org/format/#document-resource-object-relationships) objects: |
| 55 | + |
| 56 | +* `openapi:discriminator` - A string that MUST be identical to the `type` member in the containing [resource object](https://jsonapi.org/format/#document-resource-objects). |
| 57 | + |
| 58 | +Here's how an article (i.e. a resource of type "articles") might appear in a document: |
| 59 | + |
| 60 | +```json |
| 61 | +{ |
| 62 | + "data": { |
| 63 | + "type": "articles", |
| 64 | + "id": "1", |
| 65 | + "attributes": { |
| 66 | + "openapi:discriminator": "articles", |
| 67 | + "title": "Rails is Omakase" |
| 68 | + }, |
| 69 | + "relationships": { |
| 70 | + "openapi:discriminator": "articles", |
| 71 | + "author": { |
| 72 | + "data": { "type": "people", "id": "9" } |
| 73 | + } |
| 74 | + } |
| 75 | + } |
| 76 | +} |
| 77 | +``` |
| 78 | + |
| 79 | +### Atomic Operations |
| 80 | + |
| 81 | +In addition to the members allowed by the [Atomic Operations extension](https://jsonapi.org/ext/atomic/), |
| 82 | +the following member MAY be included in elements of an `atomic:operations` array: |
| 83 | + |
| 84 | +* `openapi:discriminator` - A free-format string to facilitate generation of client code. |
| 85 | + |
| 86 | +For example: |
| 87 | + |
| 88 | +```http |
| 89 | +POST /operations HTTP/1.1 |
| 90 | +Host: example.org |
| 91 | +Content-Type: application/vnd.api+json; ext="https://www.jsonapi.net/ext/openapi https://jsonapi.org/ext/atomic" |
| 92 | +Accept: application/vnd.api+json; ext="https://www.jsonapi.net/ext/openapi https://jsonapi.org/ext/atomic" |
| 93 | +
|
| 94 | +{ |
| 95 | + "atomic:operations": [{ |
| 96 | + "openapi:discriminator": "add-article", |
| 97 | + "op": "add", |
| 98 | + "data": { |
| 99 | + "type": "articles", |
| 100 | + "attributes": { |
| 101 | + "openapi:discriminator": "articles", |
| 102 | + "title": "JSON API paints my bikeshed!" |
| 103 | + } |
| 104 | + } |
| 105 | + }] |
| 106 | +} |
| 107 | +``` |
| 108 | + |
| 109 | +## Processing |
| 110 | + |
| 111 | +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. |
| 112 | +A server SHOULD ignore the `openapi:discriminator` member in elements of an `atomic:operations` array. |
| 113 | + |
| 114 | +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. |
| 115 | +The member value MUST be the same as the `type` member value of the containing resource object. |
| 116 | + |
| 117 | +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. |
| 118 | +The member value MUST be the same as the `type` member value of the containing resource object. |
| 119 | + |
| 120 | +A client MAY include the `openapi:discriminator` member in elements of an `atomic:operations` array. |
| 121 | + |
| 122 | +### Processing Errors |
| 123 | + |
| 124 | +A server SHOULD validate that the value of the `openapi:discriminator` member in |
| 125 | +[attributes](https://jsonapi.org/format/#document-resource-object-attributes) and [relationships](https://jsonapi.org/format/#document-resource-object-relationships) objects |
| 126 | +is identical to the `type` member in the containing resource object. When validation fails, the server MUST respond with a `409 Conflict` |
| 127 | +and SHOULD include a document with a top-level `errors` member that contains an error object. |
0 commit comments