Closed (outdated)
Project:
Drupal core
Version:
8.9.x-dev
Component:
jsonapi.module
Priority:
Minor
Category:
Feature request
Assigned:
Reporter:
Created:
3 Mar 2017 at 20:43 UTC
Updated:
13 Jan 2020 at 14:21 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
wim leersActually, thanks to the addition of
\Drupal\Core\Entity\EntityPublishedInterfacein #2789315: Create EntityPublishedInterface and use for Node and Comment, this is now totally feasible :)Comment #3
midas587 commentedI am working on this issue.
Comment #4
wim leers@midas587: that's great news! Also: welcome to drupal.org! 🤝
Comment #5
e0ipso@midas587 can you please assign this to yourself so others don't work on this as well by mistake?
Thanks for your contribution!
Comment #6
gabesulliceFWIW, I don't think we should be arbitrarily adding links to every response that are merely suggestions. Perhaps we can find a better way to solve this through documentation?
Comment #7
midas587 commentedComment #8
midas587 commented@e0ipso fair enough. Assigned.
Comment #9
wim leers#6: I agree, but in this case, we're adding a suggestion pointing users to what they probably want 99% of the time. I think this issue should perhaps be the sole exception?
Comment #10
e0ipsoIsn't that what HATEOAS is about? As long as they are relevant I think they belong. The challenge is to come up with links from the module's context, you need to know what the application is doing to be intelligent when adding links. As @Wim Leers is saying, I think this is one of the rare cases where we know how to generate a relevant link without application context. Another example we should consider is translations.
Comment #11
wim leers… when we figure out how to handle translations. Core hasn't figured this out yet either: #2135829: EntityResource: translations support.
Comment #12
e0ipso@Wim Leers yeah… I was just pointing out interesting potential link types. It could've been worse, I could've mentioned revisions instead! (which are also interesting)
Comment #13
wim leersYep :)
Comment #14
wim leers#2844375-38: Document excluded inaccessible entities for DX reasons was marked fixed, because documentation has been written. This would probably be even better, because it makes it more discoverable.
Comment #15
gabesulliceNot necessarily. To me, it's not about helpful links and/or permutations of filters. Or even improving DX.
HATEOAS links should be about communicating state, like "you have access to edit" or "this product is available for purchase." Links should ideally have mechanical relevance. Like a link that can be followed for the next page of results or an edit link suggesting to a frontend that the user has edit permissions and therefore should show an edit button in the UI.
We actually agree more than I'm making it sound like. I think we should add a helpful link. I just feel strongly that this shouldn't be a document level link. Let's put a link to a docs page on the error object.
Heck, let's even make sure there's an #anchor to a very specific suggestion. That would be in line with another open issue about adding error codes.
And, if you insist ;) add a link with the filter on it too!(although I think it would actually be less helpful because it wouldn't have any context). Just do it on the error object :P
Then, in an ideal world, perhaps some Drupal JS client could log the errors in the console in development mode and it could put that link to "more info" in the log message for all errors where we've made this improvement, mechanically :)
The spec even has a built-in
errors.links.aboutfor exactly that purpose.Comment #16
gabesulliceLook ma! I made docs and a link!
Comment #17
wim leersThanks for the argument/explanation in #15, that convinced me :)
The only remaining question then is: how do we determine when to (automatically) add this link to the error object? We don't necessarily know when access is not allowed due to involvement of the
statusfield.Comment #18
gabesulliceI personally don't think we should. I think the link to the docs page is enough. We don't need to include a link with a filter status, because it's not mechanically actionable. A human will be able to interpret the docs page just fine.
However, for the sake of being thorough, I imaging we could (1) look for the PublishableInterface and (2) inspect the "reason" string for the permission strings:
bypass node access,administer nodesorview own unpublished contentTo be clear, I wouldn't be in favor of doing that lol. But I wouldn't filibuster it either.
Comment #19
wim leersA hardcoded link to the error object, on every error object? It's not clear to me where that link that you're proposing would live.
Comment #20
gabesulliceAh, my bad. I posted a lot of context which you may not have seen. The error object I'm imagining can be seen in the code example under "So, what's next" in this comment: #2943176-34: Spec Compliance: when error object 'id' key exists, it contains the individual resource URI, instead of "a unique identifier for this particular occurrence of the problem"
Summary: I don't think we should a single error per omitted resource in a collection. Just a single error object when any object has been omitted because of access. The link I'm talking about would be a hardcoded link to the documentation page I made and would live on that single error object under
links.about.If you're concerned about including a hardcoded link to a d.o docs page, perhaps we could link to a line in the
jsonapi.api.phpusing the repository browser.Comment #21
wim leersOh! Well then let's postpone this on #2943176: Spec Compliance: when error object 'id' key exists, it contains the individual resource URI, instead of "a unique identifier for this particular occurrence of the problem", otherwise this is going to be too confusing. Because we'd be discussing multiple options in parallel, depending on what we do there.
Comment #22
e0ipsoHmm, I'm not sure I agree with that. I'll conceed that I used a poor wording, because HATEOAS is all about application state. However my point was on the practical side. We are not restricted to only state driving hypermedia. Hypermedia is more than that, and it's definitely appropriate to have that link under that umbrella.
I love the idea to have human readable help pages along the errors. I believe curies in the HAL spec are about that. We also had them in RESTful for the ApiProblem implementation. So it's definitely a widely supported pattern 👏🏽. Note: in RESTful the error pages were added via the
advandced_helpmodule, but I think drupal.org is the better place for that.Comment #23
wim leersComment #24
gabesullice@midas587, do you still want this one assigned to you?
Comment #25
gabesullice6 days w/o a response, I think it's fair to un-assign.
Comment #26
wim leers#2943176: Spec Compliance: when error object 'id' key exists, it contains the individual resource URI, instead of "a unique identifier for this particular occurrence of the problem" was closed, so #21 is no longer true.
Comment #27
wim leersI think you're both right.
HATEOAS is about state. For individual resources, I think the "mechanical relevance" (i.e. links for state mutations) makes sense.
But what about collections? In case of a collection, filtering it down to a subset seems reasonable too; it doesn't change application state, but it does change the "application state" per se, but it does change the "collection state", in that it's a subset. Is that permissible by HATEOAS?
(Note that http://jsonapi.org/format/ has zero mentions of HATEOAS.)
I think links providing access to different subsets of the collection is a powerful DX feature.
For example:
\Drupal\Core\Entity\EntityPublishedInterfaceimplies an entity type is (un)publishable. That allows us to automatically surface bothpublishedandunpublishedlinks.Comment #28
gabesulliceThis has gone on long enough (and that's my fault!).
It won't hurt anything and @Wim Leers makes a fair point about getting to a subset of a collection.
I like the idea of the links are available conditionally based on
EntityPublishedEntityInterfaceand toggling betweenpublishedandunpublished.Let's get it done and move on :)
Of course, it'd be great if this was a precursor to or at least forward-compatible with a good solution for customizable/extendable HATEAOS links. But let's not that block this.
Comment #29
wim leersThis still needs lots of clean-up, but shows the principle.
Comment #31
gabesulliceComment #33
e0ipsoPretty clever. I like the idea of using that interface, I didn't know it existed. One question, is the published information enforced to live in a field named
status?Comment #34
wim leersNo, it isn’t, hence”needs lots of clean-up” :) I’ll update this patch to remove the inappropriately hardcoded bits. I just wanted architectural feedback from both of you before spending more time on this!
Comment #35
wim leers#2995960: Add a Link and LinkCollection class to support RFC8288 web linking. and #3014704: Expose API to allow links handling for entities from other modules would make this a lot simpler.
This is #29 rebased on top of #2995960-54: Add a Link and LinkCollection class to support RFC8288 web linking..
Comment #36
wim leers#2995960: Add a Link and LinkCollection class to support RFC8288 web linking. landed.
That means this patch can move forward.
Comment #37
wim leersI wanted to expand this to
?resourceVersion=rel:working-copyper … but then I remembered that collection-level support for that was removed in #2992833-282: Add a version negotiation to revisionable resource types.#36 implements exactly the scope of what the issue title says.
I think it's fine to hardcode this for now. It addresses a very common need. With literally 9 LoC. That are trivial to retain BC for if needed. Eventually, this would be implemented using #2994193: [META] The Last Link: A Hypermedia Story. But doing this now addresses the current need now.
The only thing that I think really needs further attention is the relation name.
Comment #39
wim leersWow, our tests are impressively tight.
That will make it easy to add explicit tests to verify these links are present when they should be :)
Affected entity types:
Term,Node,MenuLinkContent,Media,Comment,BlockContent.Comment #41
wim leersd.o-- for automatically testing #35 even though nobody ever asked it to :(
Comment #42
gabesulliceThe entity type manager is already injected.
Should we add a condition that omits these links if a filter is already on the request?
If filters were already on the request, I think I would expect that the
publishedlink would add to or alter any existing filters, not lose them.Why
filter-*and not just(un)published?Comment #43
wim leersin #37.
I think we'd want to be careful to either use https://www.iana.org/assignments/link-relations/link-relations.xhtml link relation types or otherwise not conflict with them. Sadly, https://jsonapi.org/format/#document-links doesn't say anything about this yet.
Looking forward to your thoughts :)
Comment #44
gabesullice1. 👍
2. I think you misread this. I asked to omit the links, not to mirror the links. Mirroring the links is definitely out of scope. Does that change your response?
3. So, technically, the spec doesn't say that link keys have to be valid relation names. Ofc, it's not a coincidence that they are in the spec. I would be very frustrated if future version of the spec made this a requirement (since it precludes having >1 relation name). However, we can't be sure of that.
I proposed a format to extension relation names in #2994193: [META] The Last Link: A Hypermedia Story and we just saw the first adoption of one in #3027238: Design of the new iteration of the module (3.x):
drupal://jsonapi/extensions/consumer_image_styles/links/relation-types/#derivativeSo, following that pattern, this one would be:
drupal://jsonapi/links/relation-types/#publishedWe can elide the
extensions/<module_name>in our own link relations, obviously.Comment #45
wim leersdrupal://and notdrupal:? Whydrupal:instead ofhttps:? Why so verbose?Comment #46
gabesulliceI agree with this statement (without agreeing with conclusion that follows it).
I don't see how saying suggesting some links are more valuable at different points in an interaction than others contradicts the idea behind hypermedia. HATEOAS does not require that "links are always present".
HATEOAS suggest that links should drive interaction based on state. Thus, if there are already filters, then the state of the interaction is different than it would be without them. I think it's counterproductive if a client says "I want all the red or blue things and not any yellow things" and we say "here's a link for some green things!" or "here's a link for everything except green things!" as opposed to "here's a link for the what you have AND green things!". The latter acknowledges the state of the interaction, the former does not.
So, what I'm trying to say is that we shouldn't do the mirroring thing in this issue. We should simply do nothing for now. So that we can do the better thing later. If we do the simple implementation right now, then we won't be able to the mirroring one later for fear of breaking BC. That's why we should just omit the links when there is a state that we can't yet handle gracefully.
Extension link relation types are supposed to be URIs. I did say: "technically, the spec doesn't say that link keys have to be valid relation names."
Which was me saying, "I agree that this is super verbose for a key name, we could probably get away with just doing
publishedand adding an official link relation later (when there's a mechanism to have >1 link relation per link key in the spec).When you mint your own URIs with a custom syntax, you are supposed to use your own prefix.
Double slashes indicate a hierarchical syntax.
I wanted to create a URI namespace that any Drupal module could eventually use, without conflict. There are lots of reasons to mint URIs for things that are not link relations. For example, an (unregistered) JSON:API profile. Think: Commerce might have a JSON:API profile that's not generic enough to be registered and the profile URI would be
drupal://jsonapi/extensions/commerce/profiles/variationswhich would makeproductVariationa required resource objectmetamember and define special handling for it.Comment #47
wim leersRE: conditional presence of these links. You're absolutely right :) I was merely playing devil's advocate to ensure we though through all aspects — AFAICT we have!
So core's HAL module got this completely wrong then? (See
\Drupal\hal\LinkManager\TypeLinkManager::getTypeUri()for example.)Comment #48
gabesulliceSort of.
HAL decided to make every link relation type unique to each instance of a website. IOW:
http://wimleers.com/rest/type/node/article !== http://sullice.com/rest/type/node/article. That's okay for entity types, but it's not okay if you want to modules to be able to provide features via hypermedia and have client libraries that are able to build on those features.For example, an HTTP client library should be able to hardcode
drupal://jsonapi/extensions/commerce/links/relation-types/#add-to-cartso that a JS library/plugin could be written that works for any Drupal Commerce site, not justwimleers.com.Because we want modules to be able to define their own relations and we don't want to maintain our own registry of link relations (we'd need to vet, approve and prevent conflicts) we need to define a federated URI scheme so that modules can provide link relations that are globally recognizable without our permission. That's how I came up with this format:
jsonapi/extensions/{module_name}/links/relation-types/#{name_of_relation}^ This says: "this is a link relation type for JSON:API, provided by {module_name}"
🤔Maybe we could drop the first
jsonapisegment, it might be superfluousSo, since this is a new specification for how identifiers are assigned, we shouldn't reuse the
httpscheme.Comment #49
wim leers#48: Sorry, I read this but forgot to respond. That all sounds logical, thanks. Now that we have the rationale at least documented here on the issue, I'm fine with proceeding in that direction.
Comment #50
wim leersWhat do we want to do here?
Should we just write a simple contrib module that does this, and uses the API provided by https://www.drupal.org/project/jsonapi_hypermedia?
Comment #51
gabesulliceI'm fine the proposal in #50.
Comment #52
wim leersProject name:
jsonapi_published?Comment #53
gabesullice#52: Sure 🤷🏼♂️. TBH, if someone needs this kind of a link, can't they just add it themselves in a custom module? I personally wouldn't want to create a full project for such a small bit of functionality.
Comment #54
wim leersThe reason I bring it up is because people keep running into this time and time again. We've gotten this question so many times.
But … actually … in the past 6 months or so, I don't think we've gotten this question even once, despite the usage of the JSON:API Drupal module growing significantly. So perhaps it's now sufficiently clear, the community has learned this, and the need for this has evaporated?
Since that's my observation today (compared to when this was opened nearly 3 years ago 🙃), I am tempted to mark this . But only if @gabesullice and @e0ipso agree.
Comment #55
gabesullice+1
Comment #56
wim leersThanks @gabesullice, one more +1 needed to close this.
Comment #57
e0ipsoThis can be closed and implemented elsewhere. I wish entity keys were more reliably implemented so we could have smarter links to collections when: an entity type has a
publishkey, anownerkey, etc.There is no reason for this not to happen in a contrib module. Maybe as a submodule in
jsonapi_hypermedia.