From 9cdfd4c6e9135497fb499baabc1129705b79ed5b Mon Sep 17 00:00:00 2001 From: Tyler Kellen Date: Fri, 1 May 2015 08:39:29 -0400 Subject: [PATCH] reserve attributes in top level of resource object This walls off implementation specific keys for resource objects under the namespace `attributes`. With this adjustment, all top level members of resource objects are reserved by JSON-API. This greatly improves our ability make additive changes that fit with the current style of the specification in a post 1.0 world. This proposal was met with wide acceptance by implementors in both #573 and #588. --- extensions/bulk/index.md | 20 ++++-- extensions/jsonpatch/index.md | 54 ++++++++------ format/index.md | 132 +++++++++++++++++++++------------- index.md | 20 ++++-- 4 files changed, 143 insertions(+), 83 deletions(-) diff --git a/extensions/bulk/index.md b/extensions/bulk/index.md index d591d084a..11e97a961 100644 --- a/extensions/bulk/index.md +++ b/extensions/bulk/index.md @@ -40,12 +40,16 @@ Accept: application/vnd.api+json; ext=bulk { "data": [{ "type": "photos", - "title": "Ember Hamster", - "src": "http://example.com/images/productivity.png" + "attributes": { + "title": "Ember Hamster", + "src": "http://example.com/images/productivity.png" + } }, { "type": "photos", - "title": "Mustaches on a Stick", - "src": "http://example.com/images/mustaches.png" + "attributes": { + "title": "Mustaches on a Stick", + "src": "http://example.com/images/mustaches.png" + } }] } ``` @@ -69,11 +73,15 @@ Accept: application/vnd.api+json; ext=bulk "data": [{ "type": "articles", "id": "1", - "title": "To TDD or Not" + "attributes": { + "title": "To TDD or Not" + } }, { "type": "articles", "id": "2", - "title": "LOL Engineering" + "attributes": { + "title": "LOL Engineering" + } }] } ``` diff --git a/extensions/jsonpatch/index.md b/extensions/jsonpatch/index.md index 95c970b46..1fc36a16e 100644 --- a/extensions/jsonpatch/index.md +++ b/extensions/jsonpatch/index.md @@ -58,8 +58,10 @@ Accept: application/vnd.api+json; ext=jsonpatch "path": "/-", "value": { "type": "photos", - "title": "Ember Hamster", - "src": "http://example.com/images/productivity.png" + "attributes": { + "title": "Ember Hamster", + "src": "http://example.com/images/productivity.png" + } } } ] @@ -130,7 +132,7 @@ A server **MUST** respond to Patch operations that target a *to-many relationship URL* as described below. For all operations, the `"value"` **MUST** contain an object that contains -an array of linkage objects or an empty array, to remove all elements +an array of linkage objects or an empty array, to remove all elements of the relationship. If a client requests a `"replace"` operation to a *to-many relationship URL*, the @@ -147,12 +149,12 @@ Content-Type: application/vnd.api+json; ext=jsonpatch Accept: application/vnd.api+json; ext=jsonpatch [ - { - "op": "replace", - "path": "", + { + "op": "replace", + "path": "", "value": [ - { "type": "tags", "id": "2" }, - { "type": "tags", "id": "3" } + { "type": "tags", "id": "2" }, + { "type": "tags", "id": "3" } ] } ] @@ -171,9 +173,9 @@ Content-Type: application/vnd.api+json; ext=jsonpatch Accept: application/vnd.api+json; ext=jsonpatch [ - { - "op": "add", - "path": "/-", + { + "op": "add", + "path": "/-", "value": [ { "type": "comments", "id": "123" } ] @@ -193,9 +195,9 @@ Content-Type: application/vnd.api+json; ext=jsonpatch Accept: application/vnd.api+json; ext=jsonpatch [ - { - "op": "remove", - "path": "", + { + "op": "remove", + "path": "", "value": [ { "type": "comments", "id": "5" }, { "type": "comments", "id": "13" } @@ -255,8 +257,10 @@ Accept: application/vnd.api+json; ext=jsonpatch "path": "/-", "value": { "type": "photos", - "title": "Ember Hamster", - "src": "http://example.com/images/productivity.png" + "attributes": { + "title": "Ember Hamster", + "src": "http://example.com/images/productivity.png" + } } }, { @@ -264,8 +268,10 @@ Accept: application/vnd.api+json; ext=jsonpatch "path": "/-", "value": { "type": "photos", - "title": "Mustaches on a Stick", - "src": "http://example.com/images/mustaches.png" + "attributes": { + "title": "Mustaches on a Stick", + "src": "http://example.com/images/mustaches.png" + } } } ] @@ -283,15 +289,19 @@ Content-Type: application/vnd.api+json; ext=jsonpatch "data": [{ "type": "photos", "id": "123", - "title": "Ember Hamster", - "src": "http://example.com/images/productivity.png" + "attributes": { + "title": "Ember Hamster", + "src": "http://example.com/images/productivity.png" + } }] }, { "data": [{ "type": "photos", "id": "124", - "title": "Mustaches on a Stick", - "src": "http://example.com/images/mustaches.png" + "attributes": { + "title": "Mustaches on a Stick", + "src": "http://example.com/images/mustaches.png" + } }] } ] diff --git a/format/index.md b/format/index.md index cccacfb47..e070190ea 100644 --- a/format/index.md +++ b/format/index.md @@ -154,7 +154,9 @@ resource collections "data": { "type": "articles", "id": "1", - // ... attributes of this article + "attributes": { + // ... attributes of this article + } } } ``` @@ -188,6 +190,7 @@ the client and represents a new resource to be created on the server. In addition, a resource object **MAY** contain any of these top-level members: +* `"attributes"`: an "attributes object", providing information about a resource. * `"links"`: a "links object", providing information about a resource's relationships (described below). * `"meta"`: non-standard meta-information about a resource that can not be @@ -200,7 +203,9 @@ Here's how an article (i.e. a resource of type "articles") might appear in a doc { "type": "articles", "id": "1", - "title": "Rails is Omakase", + "attributes": { + "title": "Rails is Omakase" + }, "links": { "author": { "self": "/articles/1/links/author", @@ -212,27 +217,29 @@ Here's how an article (i.e. a resource of type "articles") might appear in a doc // ... ``` +#### Attributes Object + +The value of the `"attributes"` key is a JSON object (an "attributes object") +that represents information about the resource object it is contained within. + +The top level of this object shares a namespace with the members of `links` and +**MUST** reserve the `id` and `type` keys. Apart from these restrictions this +object can contain members keyed by any string valid for this specification. + #### Attributes -A resource object **MAY** contain additional top-level members. These members -represent "[attributes]" and may contain any valid JSON value. +All members which appear in an "attributes object" are considered attributes and +may contain any valid JSON value. Although has-one foreign keys (e.g. `author_id`) are often stored internally alongside other information to be represented in a resource object, these keys **SHOULD NOT** appear as attributes. If relations are provided, they **MUST** be represented under the "links object". -#### Complex Attributes - -"[Complex attributes]" are [attributes] whose value is an object or array with -any level of nesting. An object that constitutes or is contained in a complex -attribute **MUST** reserve the `id`, `type`, `links`, and `meta` members for future -use. - #### Fields -A resource object's [attributes] and relationships are collectively called its -"[fields]". +With the exception of the `self` link, a resource object's [attributes] and +[links] are collectively called its "[fields]". #### Resource Identification @@ -263,12 +270,10 @@ be a string. The value of the `"links"` key is a JSON object (a "links object") that represents related resources, keyed by the name of each association. -These associations share namespace with resource attributes: -associations of a given resource **MUST** be named differently than -attributes of that resource. +These associations share a namespace with [attributes]. Associations of a +given resource object **MUST** be named differently than its [attributes]. -The key `"self"` is reserved within the links object for the resource URL, -as described below. +The keys `"id"`, `"type"` and `"self"` are reserved within the links object. #### Resource URLs @@ -280,7 +285,9 @@ A resource object **MAY** include a URL in its links object, keyed by { "type": "articles", "id": "1", - "title": "Rails is Omakase", + "attributes": { + "title": "Rails is Omakase" + }, "links": { "self": "http://example.com/articles/1" } @@ -295,7 +302,7 @@ response that includes the resource as the primary data. A resource object **MAY** contain references to other resource objects ("relationships"). Relationships may be to-one or to-many. Relationships -can be specified by including a member in a resource's links object. +can be specified by including a member in a resource's [links] object. The name of the relationship declared in the key **SHALL NOT** be `"self"`. @@ -339,7 +346,7 @@ Resource linkage **MUST** be represented as one of the following: A "linkage object" is an object that identifies an individual related resource. It **MUST** contain `type` and `id` members. -A linkage object **MAY** include a `"meta"` member to contain non-standard +A linkage object **MAY** include a `"meta"` member to contain non-standard meta-information about linkage. > Note: Resource linkage in a compound document allows a client to link @@ -356,7 +363,9 @@ For example, the following article is associated with an `author` and `comments` { "type": "articles", "id": "1", - "title": "Rails is Omakase", + "attributes": { + "title": "Rails is Omakase", + }, "links": { "self": "http://example.com/articles/1", "author": { @@ -394,7 +403,9 @@ A complete example document with multiple included relationships: "data": [{ "type": "articles", "id": "1", - "title": "JSON API paints my bikeshed!", + "attributes": { + "title": "JSON API paints my bikeshed!" + }, "links": { "self": "http://example.com/articles/1", "author": { @@ -415,23 +426,29 @@ A complete example document with multiple included relationships: "included": [{ "type": "people", "id": "9", - "first-name": "Dan", - "last-name": "Gebhardt", - "twitter": "dgeb", + "attributes": { + "first-name": "Dan", + "last-name": "Gebhardt", + "twitter": "dgeb" + }, "links": { "self": "http://example.com/people/9" } }, { "type": "comments", "id": "5", - "body": "First!", + "attributes": { + "body": "First!" + }, "links": { "self": "http://example.com/comments/5" } }, { "type": "comments", "id": "12", - "body": "I like XML better", + "attributes": { + "body": "I like XML better" + }, "links": { "self": "http://example.com/comments/12" } @@ -555,11 +572,15 @@ Content-Type: application/vnd.api+json "data": [{ "type": "articles", "id": "1", - "title": "JSON API paints my bikeshed!" + "attributes": { + "title": "JSON API paints my bikeshed!" + } }, { "type": "articles", "id": "2", - "title": "Rails is Omakase" + "attributes": { + "title": "Rails is Omakase" + } }] } ``` @@ -603,7 +624,9 @@ Content-Type: application/vnd.api+json "data": { "type": "articles", "id": "1", - "title": "JSON API paints my bikeshed!", + "attributes": { + "title": "JSON API paints my bikeshed!" + }, "links": { "author": { "related": "http://example.com/articles/1/author" @@ -806,9 +829,6 @@ GET /articles/1?include=author,comments,comments.author A client **MAY** request that an endpoint return only specific [fields] in the response on a per-type basis by including a `fields[TYPE]` parameter. -> Note: Only [fields] are affected; `type`, `id`, and (optionally) `self` are -included as normal. - The value of the `fields` parameter **MUST** be a comma-separated (U+002C COMMA, ",") list that refers to the name(s) of the fields to be returned. @@ -958,8 +978,10 @@ Accept: application/vnd.api+json { "data": { "type": "photos", - "title": "Ember Hamster", - "src": "http://example.com/images/productivity.png", + "attributes": { + "title": "Ember Hamster", + "src": "http://example.com/images/productivity.png" + }, "links": { "photographer": { "linkage": { "type": "people", "id": "9" } @@ -998,8 +1020,10 @@ Accept: application/vnd.api+json "data": { "type": "photos", "id": "550e8400-e29b-41d4-a716-446655440000", - "title": "Ember Hamster", - "src": "http://example.com/images/productivity.png" + "attributes": { + "title": "Ember Hamster", + "src": "http://example.com/images/productivity.png" + } } } ``` @@ -1037,8 +1061,10 @@ Content-Type: application/vnd.api+json "data": { "type": "photos", "id": "550e8400-e29b-41d4-a716-446655440000", - "title": "Ember Hamster", - "src": "http://example.com/images/productivity.png", + "attributes": { + "title": "Ember Hamster", + "src": "http://example.com/images/productivity.png" + }, "links": { "self": "http://example.com/photos/550e8400-e29b-41d4-a716-446655440000" } @@ -1099,7 +1125,9 @@ Accept: application/vnd.api+json "data": { "type": "articles", "id": "1", - "title": "To TDD or Not" + "attributes": { + "title": "To TDD or Not" + } } } ``` @@ -1109,9 +1137,9 @@ Accept: application/vnd.api+json Any or all of a resource's attributes **MAY** be included in the resource object included in a `PATCH` request. -If a request does not include all of the fields for a resource, the server -**MUST** interpret the missing fields as if they were included together with -their current values. It **MUST NOT** interpret them as `null` values. +If a request does not include all of the [fields] for a resource, the server +**MUST** interpret the missing [fields] as if they were included with their +current values. It **MUST NOT** interpret them as `null` values. For example, the following `PATCH` request is interpreted as a request to update only the `title` and `text` attributes of an article: @@ -1125,8 +1153,10 @@ Accept: application/vnd.api+json "data": { "type": "articles", "id": "1", - "title": "To TDD or Not", - "text": "TLDR; It's complicated... but check your test coverage regardless." + "attributes": { + "title": "To TDD or Not", + "text": "TLDR; It's complicated... but check your test coverage regardless." + } } } ``` @@ -1149,7 +1179,9 @@ Accept: application/vnd.api+json "data": { "type": "articles", "id": "1", - "title": "Rails is a Melting Pot", + "attributes": { + "title": "Rails is a Melting Pot" + }, "links": { "author": { "linkage": { "type": "people", "id": "1" } @@ -1171,7 +1203,9 @@ Accept: application/vnd.api+json "data": { "type": "articles", "id": "1", - "title": "Rails is a Melting Pot", + "attributes": { + "title": "Rails is a Melting Pot" + }, "links": { "tags": { "linkage": [ @@ -1477,5 +1511,5 @@ An error object **MAY** have the following members: Additional members **MAY** be specified within error objects. [attributes]: #document-structure-resource-object-attributes -[complex attributes]: #document-structure-resource-object-complex-attributes +[links]: #document-structure-resource-links [fields]: #document-structure-resource-object-fields diff --git a/index.md b/index.md index a0c4e5f65..3052a11ff 100644 --- a/index.md +++ b/index.md @@ -27,7 +27,9 @@ Here's an example response from a blog that implements JSON API: "data": [{ "type": "posts", "id": "1", - "title": "JSON API paints my bikeshed!", + "attributes": { + "title": "JSON API paints my bikeshed!" + }, "links": { "self": "http://example.com/posts/1", "author": { @@ -48,23 +50,29 @@ Here's an example response from a blog that implements JSON API: "included": [{ "type": "people", "id": "9", - "first-name": "Dan", - "last-name": "Gebhardt", - "twitter": "dgeb", + "attributes": { + "first-name": "Dan", + "last-name": "Gebhardt", + "twitter": "dgeb" + }, "links": { "self": "http://example.com/people/9" } }, { "type": "comments", "id": "5", - "body": "First!", + "attributes": { + "body": "First!" + }, "links": { "self": "http://example.com/comments/5" } }, { "type": "comments", "id": "12", - "body": "I like XML better", + "attributes": { + "body": "I like XML better" + }, "links": { "self": "http://example.com/comments/12" } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy