Skip to content

reserve attributes in top level of resource object #588

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 1 commit into from
May 6, 2015

Conversation

tkellen
Copy link
Member

@tkellen tkellen commented May 1, 2015

This addresses the discussion in #573.

@tkellen
Copy link
Member Author

tkellen commented May 1, 2015

@bintoro, would you mind taking a look at #573 and this when you have a minute?

@tkellen tkellen force-pushed the attributes-top-level branch from 4b8ecce to 05f7e49 Compare May 1, 2015 12:44
@hhware hhware mentioned this pull request May 1, 2015
@bintoro
Copy link
Contributor

bintoro commented May 1, 2015

Whoa, wait. Why are complex attributes being removed altogether? They're a widely-requested feature.

IMO the "subattributes" within complex attributes should absolutely not be enclosed in a further attributes object. It's kind of funny, then, that there might be a links member holding outbound relationships, but I think we're just going to have to live with that.

As for what member names should be reserved inside complex attributes, I've always been of the opinion that it would be best to reserve just links. If type and possibly id are going to be valid attribute names going forward, then the same should of course apply here.

Other than that, I'm fully on board with the main idea here, i.e. introducing attributes at the resource-object level.

@tkellen
Copy link
Member Author

tkellen commented May 1, 2015

@bintoro Just trying to work through the implications of this adjustment, please consider this a working draft.

Given that "complex attributes" reserve all the same top level keys as resource objects, I think they should be subject to the same constraints. The discontinuity created by not using the attributes key in "complex attributes" is pretty untenable to me.

I would rather discard this idea and accept the risks outlined in #573 if we all can't agree on this point.

@bintoro
Copy link
Contributor

bintoro commented May 1, 2015

The discontinuity created by not using the attributes key in "complex attributes" is pretty untenable to me.

Hmm. I don't think we have to regard attributes and links as strictly parallel members. The instinct to put attributes inside complex attributes probably stems from their superficial similarity to resource objects, but we all agree they are not comparable.

Think of it this way: all attributes appear in a single attributes container, whereas links can appear anywhere to represent relationships. It's a perfectly logical structure.

@hhware
Copy link
Contributor

hhware commented May 2, 2015

Think of it this way: all attributes appear in a single attributes container, whereas links can appear anywhere to represent relationships. It's a perfectly logical structure.

@bintoro, interesting! And the rule to form paths to those links, would it be to drop attributes. from actual path only on resource level and drop links. from the actual path on any level? E.g., the actual path <resource>.links.<link> translates to <resource>.<link>, the actual path <resource>.attributes.<complex_attribute>.links.<link> translates to <resource>.<complex_attribute>.<link>, the actual path <resource>.attributes.<complex>.<attribute>.links.<link> translates to <resource>.<complex>.<attribute>.<link>, right?

@bintoro
Copy link
Contributor

bintoro commented May 2, 2015

@hhware Yes.

To put it another way, an attribute can be any valid JSON value, as promised by the spec, as long as any nested objects reserve id (?) and links members. This is a minimal restriction and would be easy to work with in the context of NoSQL datastores and existing JSON structures.

Introducing attributes inside complex attributes would essentially turn them into resource objects in their own right, which would defeat their purpose. In fact, complex attributes do not even have attributes! They just have members since they're plain JSON.

links objects, on the other hand, are OK within complex attributes because, unlike the regular members, they're a JSON API -specific thing that's always going to need a backend-to-API transformation. I hope this clarifies why I feel attributes and links are not analogous.

@hhware
Copy link
Contributor

hhware commented May 3, 2015

@bintoro, pretty smart! I agree, it could be useful to have links reserved anywhere in attributes.

reserve id (?)

I only suggested to reserve attributes.id, not id anywhere in attributes, and only because paths can include id, <attribute> and <link>, so if attributes.id were allowed, it would be unclear how to reference both <resource>.attributes.id and <resource>.id at the same time. I agree, there should be no restriction on internal structure of attributes besides these two things.

@tkellen
Copy link
Member Author

tkellen commented May 3, 2015

Introducing attributes inside complex attributes would essentially turn them into resource objects in their own right, which would defeat their purpose. In fact, complex attributes do not even have attributes! They just have members since they're plain JSON.

If complex attributes are explicitly for plain JSON and not for addressable resources it feels pretty strange to me that they would include references to addressable resources via links. That said, given that I don't personally have a use-case for complex attributes (and if I did, I doubt I'd use links within them), I suppose I can look the other way.

@bintoro, would you mind taking a stab at what the revised definition of a complex attribute would be so I can re-introduce it in the document?

I'd really like to hear from @dgeb and @steveklabnik on this. I think the main point of the PR is really important but I'm not going to merge without broad consensus.

represent "[attributes]" and may contain any valid JSON value.
A resource object **MAY** contain an "[attributes]" object. If included, this
object **MUST** reserve the `id` member at it's top level, but can otherwise
contain any valid JSON value.
Copy link
Member

Choose a reason for hiding this comment

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

I believe that type MUST be reserved as well as id. Otherwise, requests to sort or filter by type would be ambiguous.

Also: s/it's/its/

@tkellen
Copy link
Member Author

tkellen commented May 4, 2015

Is there any reason that links for complex attributes can't be represented in the top level links object via dot notation?

@dgeb
Copy link
Member

dgeb commented May 4, 2015

Is there any reason that links for complex attributes can't be represented in the top level links object via dot notation?

This would be possible using URI templates, which could account for arrays. However, URI templates are no longer explicitly supported in the spec.

@dgeb
Copy link
Member

dgeb commented May 4, 2015

Even though type and id share a namespace with members of links and attributes, I see the explicit separation of attributes as important to future-proofing the spec. It clearly cordons off user-defined fields into objects which define their meaning, and allows for future meaning to be given to groups of fields through the introduction of a new sibling to links and attributes. This could happen in the base spec or simply in additive extensions.

I'm 👍 on merging this soon to allow implementations to adapt before May 21. I would like to open a separate milestoned issue to discuss defining complex attributes and reserving members within them.

@tkellen could you please update the home page example as well?

@tkellen tkellen force-pushed the attributes-top-level branch from 626b5f9 to 9588740 Compare May 4, 2015 13:59
@tkellen
Copy link
Member Author

tkellen commented May 4, 2015

Updated. I'm prepared to merge and re-open the complex attributes issue assuming you're good with the current changes.

@bintoro
Copy link
Contributor

bintoro commented May 4, 2015

If complex attributes are explicitly for plain JSON and not for addressable resources it feels pretty strange to me that they would include references to addressable resources via links.

There is clearly a use case for outbound links from complex attributes (e.g., #238).

Whether complex attributes should be addressable has been discussed multiple times (e.g., #383), and the majority opinion seems to be against. Doing so would essentially make them embedded resource objects, which goes against the linkage paradigm.

Is there any reason that links for complex attributes can't be represented in the top level links object via dot notation?

This was discussed comprehensively in #383 and decided against. (It was actually about putting them at the resource-object level, but the idea is the same.)

@bintoro, would you mind taking a stab at what the revised definition of a complex attribute would be so I can re-introduce it in the document?

But I'm not sure what needs to be done here. Does the definition of complex attributes have to change in any way apart from what members are reserved? I'm still puzzled as to why the section is being removed.

PR #504 is aimed at improving the explanation on complex attributes, so any amendments to that section can be implemented there.

@tkellen
Copy link
Member Author

tkellen commented May 4, 2015

Sorry for not being up to speed on that particular conversation @bintoro, I have obviously not considered complex attributes carefully enough (reasons stated above). I'll re-read those issues so I have the proper context. Assuming you're fine with rebasing #504 off of this, would you feel comfortable having me merge this as is?

@bintoro
Copy link
Contributor

bintoro commented May 4, 2015

Assuming you're fine with rebasing #504 off of this, would you feel comfortable having me merge this as is?

Yeah, it's fine to recreate the removed section in #504. In fact, the definition of complex attributes is not even strictly necessary; it only exists to elaborate on the topic because questions about it have been raised repeatedly. JSON objects as attributes have always been allowed regardless.

However, there are a few other things I would like to discuss. Apologies for raising these issues at such a late stage, but I've been occupied with other stuff.

  • There is no longer a definition for attributes, yet the spec refers to the term in a number of places. The Attributes section only talks about an attributes object.

  • If included, this object [...] can otherwise contain any valid JSON value.

    This doesn't seem right. An attribute can have any valid JSON value; the attributes object may contain any number of those.

  • MUST reserve the id and type members

    I didn't realize until now that type would continue to be reserved. In proposal to reserve "attributes" member at top level of resource objects #573 it seemed that part of the support for the whole idea was based on the premise that type would become available as an attribute name.

    If resource-object-level scalar members and attributes will continue to share a namespace, the value of this proposal will be reduced quite a bit. If further special members are introduced in the future, we'll have a situation where some such members share a namespace and some don't.

@hhware
Copy link
Contributor

hhware commented May 4, 2015

If resource-object-level scalar members and attributes will continue to share a namespace, the value of this proposal will be reduced quite a bit.

I suggest to add a clear statement that the following resource members are addressable via namespace <resource_name>.*

  • specifically in the following places: sort, fields[TYPE] (anywhere else?):
    • id,
    • type (if it is declared addressable, and if so, it should obviously be reserved in attributes and links),
    • members of <resource_name>.attributes and their descendants via dot-separate paths,
  • specifically in the following places: include (anywhere else?):
    • members of <resource_name>.links and their immediate descendants.

This will

  • make the spec more readable, especially to newcomers (currently the only reference to namespace <resource_name>.* seems to be in http://jsonapi.org/format/#document-structure-links),
  • enable other query parameters introduced by extensions or implementations to address other resource member and their children via paths, e.g., to enable query parameters like resource_members_enabled=meta.some_meta_member,some_resource_level_member in the future.

@tkellen
Copy link
Member Author

tkellen commented May 4, 2015

No worries @bintoro.

I was originally thinking type would remain available, but @dgeb makes a good point about the ambiguity for sort and filter. I suppose we could specify an order of preference for them to gain that back?

I see your point about the difference between attributes and the attributes object. I'll push a fix for that shortly.

@tkellen tkellen force-pushed the attributes-top-level branch 2 times, most recently from f8836e5 to e9140b5 Compare May 4, 2015 17:35
@ethanresnick
Copy link
Member

@bintoro

If resource-object-level scalar members and attributes will continue to share a namespace, the value of this proposal will be reduced quite a bit. If further special members are introduced in the future, we'll have a situation where some such members share a namespace and some don't.

That was my first reaction too when @dgeb mentioned that they'd share a namespace. Now I'm wondering though if having them be separate namespaces would also cause problems, like the ambiguity with type in sort that @hhware alluded to. @tkellen's suggestion to solve that with an order of preference could work for type, but what happens when we add a new sibling to "attributes" down the line, and someone has an attribute with the same name (as our new member) that they're using in ?sort requests. Then, suddenly, our new resource-object-level field can't be sorted on.

I see a couple solutions:

  1. We could distinguish in query parameters between top-level members (meaning, members at the top of the resource-object) and attributes/links. So, for concision, all top-level members could be referenced as top.[key-name]. So you'd have ?filter[top.id]=myJSONAPIID distinct from ?filter[id]=valOfIdInAttributes. That would offer real extensibility then, and any hing we reserved in the "attributes" object would be only to avoid confusion (e.g. it might be good to reserve id) or to enable other types of extensibility (like reserving "links" within complex attributes).
  2. While I think Option 1 is a decent answer to the problem at hand, I still worry that we're going to run into cases down the line where we want types of extensibility that the current spec doesn't give us. For example, we might want to add a member at the document's top-level that conflicts with the behavior of a commonly-used extension. To solve this problem, I think we should consider the more conventional solution of a reserved-word list (which has saved javascript, e.g., as it's tried to grow without breaking bc). These reserved words might not apply to attribute or link names (since it's hard for people to change their data models), but they could apply to the names of members that extensions are allowed to add.

@cziegenberg
Copy link
Contributor

Doesn't a collection of resources that can be sorted/filtered always contain resource objects of the same resource type? It's not defined in the spec, but this is how I understand it - so IMHO sorting/filtering by (resource) type doesn't make sense here and only id needs to be reserved.

@bintoro
Copy link
Contributor

bintoro commented May 4, 2015

This may be beating a dead horse, but what was it about reserved-key prefixes that caused them not to catch on? I don't remember seeing any concrete objections apart from underscore prefixes being considered ugly, which I agree with. But there are other characters.

It seems to me we're going through a whole lot of trouble here to solve issues that wouldn't exist to begin with if we just used @id, @type, and so on.

@hhware
Copy link
Contributor

hhware commented May 4, 2015

We could distinguish in query parameters between top-level members (meaning, members at the top of the resource-object) and attributes/links. So, for concision, all top-level members could be referenced as top.[key-name]. So you'd have ?filter[top.id]=myJSONAPIID distinct from ?filter[id]=valOfIdInAttributes.

Perhaps we could provide a different syntax to refer to resource-level member names? E.g., immediate children of resource can be referenced by enclosing it in <> or some other braces, and others are referenced directly? Examples:

  • id: both articles.<id> articles.id refer to the same thing because id is reserved (if it is reserved),
  • articles.<type>, type is not reserved,
  • articles.<links>.author.linkage could be used in requests to, e.g., enable linkage member of author, whereas articles.author could be used to refer to relationships,
  • articles.<meta>, articles.<new_resource_level_member>, etc

Doesn't a collection of resources that can be sorted/filtered always contain resource objects of the same resource type?

@ziege, no, heterogeneous collections are also supported

@dgeb
Copy link
Member

dgeb commented May 4, 2015

In the current spec, attributes and links already share a namespace (see http://jsonapi.org/format/#document-structure-links). Although it's not explicitly stated, this namespace is also shared by type and id.

I don't think this should change if we accept this PR. I am unclear on the value proposition of allowing an attribute named type in addition to a resource's type. Furthermore, it would be surprising to encounter a link named contact along with an attribute named contact in the same resource. These allowances would just lead to confusion.

Instead, I see the value proposition of the attributes object to be that it clearly walls off user-defined attributes from spec-defined members, such as type, id, and links. It allows for the introduction in the future of a sibling to meta or links without breaking backward compatibility. These future members could define fields with unique requirements and shared characteristics.

Let's say that an extension introduces the embedded member additively. It would live alongside type, id, links, meta, and attributes. It's very important to note that embedded would not conflict with an attribute already named embedded (say, a boolean particular to a resource). Inside the embedded object might reside other properties that share the same per-resource namespace as type, id, links, and attributes.

I hope this example illustrates the (somewhat subtle) advantages of the attributes member. By walling off user-defined attributes from spec-defined attributes completely, we can avoid custom prefixes while still keeping the spec relatively future-proof.

@hhware
Copy link
Contributor

hhware commented May 4, 2015

Furthermore, it would be surprising to encounter a link named contact along with an attribute named contact in the same resource. These allowances would just lead to confusion.

@dgeb, if you are referring to my comment, I only suggested to clearly state that they all share the same namespace <resource_name>.*, not to split it in multiple namespaces.

@tkellen tkellen force-pushed the attributes-top-level branch 6 times, most recently from 0052dbf to c1b320f Compare May 6, 2015 13:00
tkellen pushed a commit that referenced this pull request May 6, 2015
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.
@tkellen tkellen force-pushed the attributes-top-level branch from c1b320f to 60561b5 Compare May 6, 2015 13:12
tkellen pushed a commit that referenced this pull request May 6, 2015
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.
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.
@ethanresnick
Copy link
Member

@bintoro Amidst all this we lost the section on complex attributes, and the members reserved in them. Would you be up for making a PR (or rebasing from your old ones/old text) to bring this back?

@bintoro
Copy link
Contributor

bintoro commented May 20, 2015

@ethanresnick Sure. But what to reserve? I'm inclined to reserve as few keys as possible. Do you foresee a need for anything besides "relationships"?

@ethanresnick
Copy link
Member

@bintoro Definitely relationships, but I'm also inclined to reserved attributes (to communicate that this isn't another resource object), and I might also reserve links just in case. But I don't think we need to reserve type/id, especially if we're reserving attributes.

@bintoro
Copy link
Contributor

bintoro commented May 21, 2015

I'm also inclined to reserved attributes (to communicate that this isn't another resource object)

@ethanresnick Could you elaborate on this, please? I mean, how does reserving attributes help to draw a distinction between an object-as-an-attribute and a resource object?

Reserving links for now might be a good idea, just to be on the safe side, but if no one is able to foresee a use case for it, I'd be in favor of dropping that restriction eventually.

@ethanresnick
Copy link
Member

@ethanresnick Could you elaborate on this, please?

Sure. I said that because, when we were initially discussing the introduction of attributes at the resource object level with @tkellen, his first instinct (if I'm remembering correctly) was that complex attributes should have an attributes member within them. It quickly became clear that that wouldn't make sense, because complex attributes aren't embedded resources. But if Tyler was getting tripped up by this, I'm sure others will too. Everyone's in a hurry and will maybe only skim the section, whatever. So this restriction is just a simple way to emphasize the point; when people come across it, they'll be forced to have that "aha, so this is a different thing" moment.

@bintoro
Copy link
Contributor

bintoro commented May 21, 2015

@ethanresnick Interestingly I have the exact opposite view 😄 The less similarities there are between complex attributes and resource objects, the less opportunity for confusion.

In fact, I would like to get rid of the concept of "complex attribute" altogether and simply point out that an object or array is indeed a valid value for an attribute. Or perhaps retain the term but not have a separate section to discuss them.

@ethanresnick
Copy link
Member

The less similarities there are between complex attributes and resource objects, the less opportunity for confusion.

Ohhhh, I see what you mean. You're thinking that users will assess similarities by looking at the definitions (so reserving attributes would make the definition more similar), whereas I was assuming they'd assess similarities by looking at example payloads, and preventing attributes would force the payloads to look more different. But now that I think it through, I'm not sure where they'd get those example payloads from, so your point of view probably makes more sense. Let's do what you're suggesting then: only reserve relationships and links, downplay complex attributes in terms of sections and then, perhaps, discreetly slip a complex attribute into one of the examples, and have that complex attribute happen to not use the attributes key.

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.

6 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