Skip to content

only top-level member may be defined by extension #1642

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 2 commits into from
Jul 27, 2022

Conversation

jelhan
Copy link
Contributor

@jelhan jelhan commented Jul 27, 2022

An extension may introduce it's own top-level member. E.g. the atomic operations extension defines the additional top-level members atomic:operations and atomic:results.

So far the specification enforced that a JSON:API document has either data, errors or meta top-level member. Even if there is another top-level member introduced by an applied extension.

This is not desirable. And it was not intended. It is likely that some implementations would ignore that requirement. Even the examples given in official atomic operations extension are ignoring it:

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

{
  "atomic:operations": [{
    "op": "add",
    "href": "/blogPosts",
    "data": {
      "type": "articles",
      "attributes": {
        "title": "JSON API paints my bikeshed!"
      }
    }
  }]
}

A meta top-level member with an empty object could be added to fulfill that requirement. The example payload from atomic operations extensions would be changed like the following:

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

  {
    "atomic:operations": [{
      "op": "add",
      "href": "/blogPosts",
      "data": {
        "type": "articles",
        "attributes": {
          "title": "JSON API paints my bikeshed!"
        }
      }
-   }]
+   }],
+   "meta": {}
  }

But there doesn't seem to be any value in doing so. Instead we should relax the constraint of the base spec to better support this use case of extensions.

I see two potential options to address the issue:

  1. We could relax the base spec to not enforce any top-level member. To do so, we would replace MUST with MAY in the sentence.
    - A document **MUST** contain at least one of the following top-level members:
    + A document **MAY** contain at least one of the following top-level members:
  2. We could keep the requirement but add top-level members defined by an applied extension as a forth option.
      A document **MUST** contain at least one of the following top-level members:
    
      * `data`: the document's "primary data".
      * `errors`: an array of [error objects](#errors).
      * `meta`: a [meta object][meta] that contains non-standard meta-information.
    + * a member defined by an applied extension.

I tend toward the second approach:

  • A JSON:API document without any top-level member would not have any value. I think we should disallow this case in the base spec.
  • Allowing a JSON:API document without data, errors or meta top-level member even if no extension is applied, could be considered a breaking change.
  • As extension did not exist in v1.0 changing semantics only in case an extension is applied, is not a breaking change.

@jelhan jelhan added this to the v1.1 milestone Jul 27, 2022
@jelhan jelhan requested a review from dgeb July 27, 2022 08:17
Copy link
Member

@dgeb dgeb left a comment

Choose a reason for hiding this comment

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

Thanks for addressing this, @jelhan. I agree with this approach and the clear wording you've used. I think it just needs a link back to the extensions section.

Co-authored-by: Dan Gebhardt <dan@cerebris.com>
@dgeb dgeb merged commit ebd2b47 into gh-pages Jul 27, 2022
@dgeb dgeb deleted the relax-top-level-member-constraint-for-extensions branch July 27, 2022 12:14
@Art4
Copy link
Contributor

Art4 commented Jul 22, 2024

@jelhan I'm sorry for not following this topic earlier, but allowing extensions to define the only member in top-level document is a breaking change.

  • Allowing a JSON:API document without data, errors or meta top-level member even if no extension is applied, could be considered a breaking change.

This is really the case here: A 1.0 parser ignores the atomic:operations member and is left with a top-level member without any member at all, which is invalid.

1.0 requires at least data, errors or meta as a top-level member, so your example with an empty meta member is a valid workaround.

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

  {
    "atomic:operations": [{
      "op": "add",
      "href": "/blogPosts",
      "data": {
        "type": "articles",
        "attributes": {
          "title": "JSON API paints my bikeshed!"
        }
      }
-   }]
+   }],
+   "meta": {}
  }

Sure, this workaround is a bit annoying, but would keep BC with 1.0. The same goes for relationship objects, see #1644.

The changes in this PR should be part of 2.0 instead of 1.1. And the examples in the atomic extension should mention this temporary workaround until 2.0 is released.

@jelhan
Copy link
Contributor Author

jelhan commented Jul 24, 2024

@Art4 Content negotiation between client and server prevents that issue. A client requests that a server applies an extension via Accept request header. If the server does not support v1.1 (or if it does not support that specific extension), the server must reject the request with a 406 Not Acceptable response.

@Art4
Copy link
Contributor

Art4 commented Jul 25, 2024

@jelhan Good point, thank you very much. Sadly this way version 1.0 is not forward compatible with 1.1, but at least 1.1 is backward compatible to 1.0.

My mistake was that after reading e.g. this comment I assumed that JSON:API would be forward compatible.

I will adjust my parser with this in mind. Thank you for your patient.

@jelhan
Copy link
Contributor Author

jelhan commented Jul 25, 2024

It's forward compatible. A server implementing v1.0 handles every request to apply an extension as not supporting that specific extension.

But I see that it gets problematic if a library only implements parts of the processing rules. In your case the library seems to be limited to parsing a JSON:API document. But not implementing the content negotiation. I would recommend to document in that case that it only supports JSON:API documents without any extension applied. As extensions can define additional processing rules, a JSON:API document cannot be parsed ignoring applied extensions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
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