Closed (fixed)
Project:
Decoupled Menus
Version:
1.0.x-dev
Component:
Code
Priority:
Normal
Category:
Feature request
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
3 Feb 2021 at 16:54 UTC
Updated:
31 Mar 2021 at 18:39 UTC
Jump to comment: Most recent
Comments
Comment #2
gabesulliceI started working on this in the issue fork linked above. Rather than invent our own format, I've been prototyping the endpoint using Linkset draft as the format for a use case #1. It has not been adopted as an RFC, but it has been picked up by the IETF's HTTP API working group and I expect it to be adopted without too many changes. Since this is technically a contrib module, I think working from a draft is fine for the time being. This is actually an nice opportunity to contribute outside the Drupal ecosystem and the internet more broadly.
If we use this draft, we could make a JavaScript library for it that would be useful outside of the Drupal ecosystem, just like the
oncelibrary 🙂You can see exactly what the endpoint is expected to look like in the tests. This is what I have so far:
/system/menu/{menu}/linkset{menu}is a parameter for a menu config entity's machine name.Comment #4
gabesulliceGonna do a self-review, but would appreciate a first pass from another reviewer too :)
Comment #5
vulcanr commentedJust did a very superficial review, and looks fine to me - good to see things moving!
Comment #6
decipheredI have installed the module(s) and done some basic testing.
Thoughts so far:
- Not being JSON:API seems inconsistent with the existing decoupled architecture of Drupal, and will require a seperate client for consumption.
- There doesn't appear to be any way to filter the results, or get additional data.
I will be working on a prototype of the DruxtMenu node module to add support for the modules to do further testing: https://github.com/druxt/druxt-menu/issues/44
Comment #7
decipheredI've put together proof of concept support in the DruxtMenu module.
The data structure was a bit odd, with both the
linksetandlinkset[#].item[#]['drupal-menu']providing arrays of objects.The
linksetbeing an array makes me think that it's possible to get multiple linksets from a single endpoint, for translation support or similar. But I test with Umami, and this does not seem to be the case:-
/system/menu/main/linksetonly returns the English results-
/es/system/menu/main/linksetonly returns the Spanish results.The
linkset[#].item[#]['drupal-menu']seems more unusual, as it implies a single link can have multiple hierarchies.The absence of a unique ID per link is also a problem for me. In my case I constructed an ID using the menu name and the hierarchy.
Comment #8
gabesulliceThanks for trying it out @Deciphered! I really appreciate it!
I don't think we need/should make media type-specific clients. Let's just make code that works with Drupal. A Drupal client can use
application/vnd.api+jsonfor resources,application/schema+jsonfor schema, andapplication/linkset+jsonfor link sets (e.g. menus).JSON:API 1.1-RC3 has support for JSON Schema integration via the
describedbylink. So it's not unprecedented to use mixed formats for mixed purposes with JSON:API (so long as it's all JSON).I think both of these go beyond the scope of this issue. Beyond this issue, I think a JSON-RPC plugin makes the most sense for these kinds of things.
The format is entirely driven by https://tools.ietf.org/html/draft-ietf-httpapi-linkset-00.
This initially confused me too. There is no way to represent multiple linksets. From my understanding, the reason for the top array is to support different
anchorswithin a single linkset. Thedrupal-menuarray is required by the draft. Specifically, it says:I plan on writing a little JS today to denormalize the linkset representation into something more easily consumable. Mind if I ping you to give it a whirl?
Comment #9
gabesulliceThat's awesome! I didn't intend this, it's just a consequence of using the menu tree loader, I think.
Comment #10
decipheredPing away, no need to ask permission (for me, I consent).
I also agree that we shouldn't make media type-specific clients. What I'm referring to is the pre-existing abundance of JSON:API node modules that work for the existing JSON:API that is baked into core, no longer being able to consume/transform all the types of available data.
It potentially means requiring more frontend modules to consume the data, or making/using new client modules that have to support multiple standards.
Comment #11
nod_some data for the hierarchical/flat discussion:
parent_idkey and a children key made of comma separated values of the children ids: https://magento.redoc.ly/2.4.2-guest/#operation/catalogCategoryListV1Get...parentkey https://developer.wordpress.org/rest-api/reference/taxonomies/subtreekey https://docs.bolt.cm/4.0/menus/detailed#jumpbuttonchildrenkey https://docs.apostrophecms.org/core-concepts/pages-and-navigation/connec...belowkey (in templates)From those few examples, the hierarchical construct is not too common, other big CMSs tend to refer to the immediate parent.
Also the linkset spec is not suited for menu type things, it exists to replace/improve http link headers.
Comment #12
vulcanr commentedJust to add - Shopify also gives back just a `parent_id`
Comment #13
gabesulliceI don't care very much about the
hierarchyidea. We can convert it to a parent/child representation if y'all feel very strongly about it for aesthetic reasons. I agree that it is less shocking, but I want to make sure we understand that it has some real drawbacks in terms of ease of use and response size.For example, these two bits of pseudocode contain equivalent information:
If you have a
parentproperty, then every object must also have anidbecause you must have an ID to reference. Therefore, we will have to invent IDs, or expose the link plugin IDs. This is more verbose and I was trying to avoid that because it exposes implementation details, like which modules are installed.Using plugin IDs will also encourage clients to hardcode IDs. For example, if we supply the plugin ID
user.logout, clients will be tempted to filter and hardcode something against it. I didn't want to promote that pattern since I would like to promote link relations for these kinds of things in the future. In that particular example, theuser.logoutlink is actually the login link if you're not authenticated. That would be confusing!Note that while not explicitly an ID,
`${drupal-menu.name}:${drupal-menu.hierarchy}`does form a unique value if you need one for some reason, like @Deciphered discovered at the end of #7.If you have a
parentproperty, then you must also have aweightproperty (if you want to be explicit about order).Now, some code examples showing how easy the value is to work with:
Get subtree of "/bar":
Get direct parent of "/qux":
Get grandparent of "/qux":
Get links with max depth 2:
Is some link a descendant of another link?
Comment #14
nod_Thanks for the details, that is what was missing for me. It's the kind of informations I wanted when I said "we need to clear up what it's optimized for". So a hierarchy like this is better than the "usual" parent/id thing because it's smaller in the json response, doesn't expose internal ids, it's easier to figure out the parent/child relationship across any levels (and not just one level at a time like with parent/id), easier to target a whole branch of the menu at once.
With that kind of arguments I'm happy to not do what the others are doing. This is the kind of thing we really need to explain in our documentation, to make people understand why we didn't go with the usual parent/id thing. We might even make it easy to go back to a parent/id format with a small code snippet that people can use if they really don't like this hierarchy thing.
I don't mind the fact that there is no stable id that people can (ab)use. They'll find another way and hopefully that doesn't mean they'll look at the actual URL to do this type of thing.
Comment #15
gabesulliceRebased on top of #3202608: Remove the original implementation code so that we can run tests on Drupal CI.
Comment #16
gabesulliceI think this is ready to go.
Comment #17
nod_That looks good to me. Should the padding be configurable? to handle menus with more than 1k links on one level?
Comment #20
gabesulliceThanks for the review @nod_! I created a follow up for that issue.