Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
The question of being able to get all nodes regardless of bundle keeps coming up time and time again, for example #2867456: Heterogeneous node resource [TODO: insert MORE links to such support requests here]. Clearly this is a common need.
Proposed resolution
?
Remaining tasks
Decide on approach.
User interface changes
None.
API changes
Additional routes.
Data model changes
None.
Comment | File | Size | Author |
---|---|---|---|
#4 | 2956414-4.patch | 5.01 KB | Wim Leers |
Comments
Comment #2
gabesullice+1! Great idea :)
Comment #3
Wim LeersThe current design/architecture/limitation was agreed upon in #2751985: [FEATURE] Add a bundle level relationship to entity level resources.
Comment #4
Wim LeersInitial implementation. Still very rough, but actually does work!
Comment #5
Wim Leers#2867456: Heterogeneous node resource is probably the oldest such support request/feature request. We can link many more.
Comment #6
dawehnerMaybe we could also mention that due to having different fields it would be impossible to generate a schema for them.
Comment #7
Wim Leers#6++
Any other remarks, @dawehner?
Comment #8
gabesulliceFirst, let me say that I really like this idea. If we're not going to support the bundle-agnostic route, having a route there is a win :)
Ubernit: "JSON API" is always the correct human-readable form (not JSONAPI, JSON:API, JsonApi, JSON-API, etc). See the spec introduction.
I would actually change the language to something similar to
jsonapi.api.php
to be more accurate:That's because the comment and the remark in #6 are not technically accurate. We certainly could sort by a missing field and filter by it as well. For sorts, you just follow the rules "NULL is < any value" and "filter by X implies X must exist". As for schema, it's entirely feasible to have a schema for a heterogenous collection (more below, but only if you want to get into the weeds).
The specification makes no prescription about single type routes. In fact, it makes no prescriptions about URLs at all.
We know that a route can support heterogenous types because of any of the
related
routes permit this. This is even implied by the spec because every resource object must carry atype
andid
member (instead of justid
), even on the individual route.To make a long story short, the spec is "loudly" silent about URLs as they relate to resource types, I believe specifically to not preclude this use-case (it is simply left as a recommendation that URLs are formed from types).
Finally, JSON Schema is entirely sufficient to support it too (search for "oneOf" here: http://json-schema.org/example2.html).
Comment #9
e0ipsoI like the idea to have special handling. However I'd like to respond with a 404 with the aforementioned links. I think that it is an error to construct a URL manually (use links!), and there is no content under that route hence a 404 seems more adequate. On top of that throwing a 4xx error conveys manual URL construction is wrong, dont's do it..
I would even be on board of adding manual URL construction is wrong, dont's do it. to the error message in the details section. Hehe.
As a side note I'd like to stop merging code until we have a candidate for the core patch. That's blocked by the test coverage and the 2.x branch. Therefore setting this to go against 2.x.
Comment #10
e0ipsoComment #11
gabesullice👏👏 yes.
Comment #12
Wim Leers@gabesullice: would you mind incorporating your feedback in the patch? Easier for you to make the changes you would like than for me to try to interpret everything correctly.
@e0ipso: hm, semantically 404 is wrong and 300 is right — but I agree about DX/sending developers an unambiguous signal.
Comment #13
dawehnerAs part of the javascript modernisation initiative we realised that
/admin/content
in its current form kinda needs a way for you to fetch nodes across bundles.Comment #14
Wim LeersI think I heard @tedbow has been working on some code for this?
Comment #15
e0ipso@dawehner is there a strong UX reason to mix nodes of different bundles together but not mix other entity types? It has always been very confusing for Drupal newbies in my experience.
Could this be our chance to break away from that (anti?)pattern?
Comment #16
tedbow@Wim Leers I am working adding this ability to the support module for React decoupled admin ui https://github.com/jsdrupal/drupal-admin-ui/pull/96
This is support building the /admin/content page in the React app which of course needs to get a collection of node across bundles and needs filtering, sorting and pagination.
Basically it creates collection-only GET resource at /jsonapi/[entity-type]
The items under
data
in the collection would still point to /jsonapi/[entity-type]/[bundle]/[uuid]So you could not POST to /jsonapi/[entity-type] and there is no route at /jsonapi/[entity-type], so no PATCH, DELETE, or GET there.
Right now it has to replace the
jsonapi.resource_type.repository
service so that it provide additional resources that use a resource type that extends\Drupal\jsonapi\ResourceType\ResourceType
this is only to provide a different path.It also has to replace the
jsonapi.request_handler
service to overrideresourceFactory()
to return a different resource typeCrossBundlesResourceType
. Right nowCrossBundlesResourceType
only overridesgetCollectionQuery()
to add the bundle condition.If a ResourceType could specify a controller class then would not need to override the
jsonapi.request_handler
service.The current logic make incompatible with jsonapi_extras because it also needs to replace the
jsonapi.resource_type.repository
service. And even if that wasn't the case the fact that it uses different resource type means the new resources would not be configurable if the both were enabled.@gabesullice had mentioned making a
service_collector
that would collect repository services. That would at least mean I would not need to replace the main repository service.Comment #17
gabesulliceVery small correction: I didn't mention alternative repositories. I think the resource repository should remain untouched. I proposed an alternative collection provider based on the concept introduced here: #2956353: [Experiment] Move fancy filtering to submodule.
This would mean that there would be no conflict w/ JSON API Extras.
Comment #18
tedbowRe #15
I do think there is UX to mix entities across bundles of the same entity type more that entities from different entity types
I am saying it would never be useful to mix entities from different entity types but for entities of the same entity types:
hook_ENTITY_TYPE_[something]
hooks which tends to encourage entities of the same type behaving the more similarly than other entity types. This has effect on user perceive them.I do think there are different entity types which the users might have a difficult time distinguishing such as:
Comment #19
e0ipsoI think I disagree WRT the UX implications but I just don't have the credentials to say so. 😂
I asked @ckrina to chime in from the UX perspective. She is under incredible demand 😛, but let's see if she can find the time at some point.
Comment #20
ckrinaSorry @e0ipso I totally forgot to comment here :P
I guess the key question is who is this page for and what knowledge, experience or UI options are available. My first answer for a site builder experience would be to have a list with all of them, but in a content author perspective separating them makes sense if we're talking about really different entities like user profiles vs commerce products.
Do you think it might be worth talking about this in the next UX meeting (Thursdays 19:30h UTC)?
Comment #21
Wim LeersThe 2.x branch is opened. Time to make a decision.
We first had consensus to just return a 404 response with helpful information.
But now (since #13 and #16), there is a strong desire to be able to access a collection (and query/filter/sort it) across all bundles of an entity type. AFAICT it's a blocker to the JS Modernization Initiative.
I am not opposed to it. What do others think?
Comment #22
e0ipsoI am strongly opposed to this in the base JSON API module. I'm OK with it in a sub-module.
Comment #23
gabesulliceI would love to see this happen.
Okay, so I think that this means we have maintainer consensus that
drupal/jsonapi
should ship with code that supports mixed-bundle collections.We're not sure how, or in what form yet though... but that's okay :)
Let's open the feature request issue for it and have that discussion!
Comment #24
gabesulliceActually, nothing got committed to this. Let's just change the title+scope.
Comment #25
gabesulliceI think I know why you feel this way, but I'm certain most don't. @e0ipso, can you elaborate and lay out your thoughts, fears, concerns, hopes, dreams (maybe deepest, darkest secrets) about this. It seems your position is softening a bit, but I know you've given it a lot of thought and we shouldn't miss out on all that brain-time.
Comment #26
Wim LeersI know you've expressed why you feel like this before. I felt the same way at some point. Can you re-explain why you feel this way? Feel free to just copy/paste previous comments from yours :) I just want to make sure we all fully understand.
Comment #27
e0ipsoI'll try to find more time to paste those (I think there's even a video of it).
When I said sub module I meant a different module. Sorry for misspeaking. I was thinking about the jsonapi_extras namespace or something of its own.
Comment #28
Wim LeersLooking forward to more detailed rationale.
Because this actually seems like a quite valuable feature addition. Not only requested by Drupalists. Also requested by e.g. Ed Faulkner at #2867456: Heterogeneous node resource, who is not a Drupalist and a contributor to both Ember.js and JSON API.
Comment #29
Wim LeersQuoting http://jsonapi.org/format/#crud:
If you search for , you find 15 issues. I think the most important issue is https://github.com/json-api/json-api/issues/365, where somebody complained about making JSON API's spec more complex for supporting heterogenous collections/polymorphism. RC2 added that in a milder form in https://github.com/json-api/json-api/pull/341, after RC1 removed it in a more invasive form in https://github.com/json-api/json-api/pull/237.
Basically, the fact that
type
is required everywhere is why polymorphism/heterogeneity is supported.If you read those issues, you'll see that the JSON API spec allows this, but doesn't provide detailed guidelines for it.
I think that supporting
/jsonapi/node
with the following restrictions would be feasible:GET
?filter
and?include
support only base fieldsComment #30
Wim LeersThe JSON API maintainers (@e0ipso, @gabesullice and I) just had a call about this. @e0ipso feels very strongly that we should not support this in the JSON API module because it creates confusion: A) the current support for collections is simpler (true!), B) most projects can live without this (probably also true), and therefore he'd prefer to see this added by a contrib module.
Comment #31
mglamanI'm completely fine with this if the API is not so constricted. I have yet to reivew #2960766-5: Support ResourceType which may have a null bundle defined.
Any site using Search API or Drupal Commerce will need this.
Comment #32
Wim LeersThis was just requested again at #2994304: Get all nodes in a single request, regardless of type. Marked it as a duplicate.
Comment #33
sorina.hriban CreditAttribution: sorina.hriban commentedSorry for not seeing this issue before creating the other one.
I think all sites at some point might need this request, not only those who are using Search API or Drupal Commerce.
In my case, I want to list all the nodes and after that to sort them or to add some filters. On the way it is now, I cannot do it.
For the user entity, there is the functionality that list all the users. Why cannot be made like this for the other entities?
Comment #34
e0ipsoNone of the projects I have been involved with needed this feature. Everyone I talked about this, outside of Drupal, think it's an anti-pattern. However, I think we can implement some sort of heterogeneous collections with reduced JSON API features in a separate module.
Comment #35
Wim LeersNote that you would only be able to filter on base fields, because filtering on fields that only exist on some of the node bundles (content types) does not make sense. (For example
page
may have afoo
field,article
may have abar
field).The
user
entity type does not support bundles, and hence it is guaranteed that the same set of fields exists across all of them. This also evident from the fact that only/jsonapi/user/user
exists, whereas for nodes, it's/jsonapi/node/article
,/jsonapi/node/page
, and so on.Comment #36
sorina.hriban CreditAttribution: sorina.hriban commentedOn my listings, I use only the base fields for filters.
Aware that user entity is a little different from the other entities, but using only the base fields for nodes, it will be the same thing. I could get only the nodes(from all content types) that are published, for example.
But what about an integration with views?
Comment #37
Wim LeersThis has been brought up in discussions occasionally. No concrete plans for it yet. It's a feature request we'd consider. But it's extremely hard to make it rock solid.
True. I agree. I'm in favor of supporting this. But my fellow maintainers aren't :) So I choose to work on those things where there is agreement from all maintainers. Sorry for the inconvenience. But for now, you can continue to make multiple requests.
Comment #38
Wim Leers#2960766: Support ResourceType which may have a null bundle defined. is closely related.
The
jsdrupal
team's JS admin UI also needs this, and hence has a support module that layers support for this on top of the JSON API module, see https://github.com/jsdrupal/drupal-admin-ui-support-dist/tree/master/mod....Comment #39
e0ipsoLet's move this to JSON:API Extras per #27, #30 and #31.
Agree?
Comment #40
Wim LeersActually, @gabesullice made a really interesting observation yesterday, at #3017047-3: Allow filtering by `type`. See my reaction at #3017047-5: Allow filtering by `type`. Let's make sure we understand that first?
Comment #41
effulgentsia CreditAttribution: effulgentsia at Acquia commentedSo what you're saying there is that it's already the case that the jsonapi module supports mixed-bundle collections. For example, on the Article bundle, if you create a mutlivalued ER field (e.g., "Related Content") that can target both Article and Page nodes, and then create an Article that actually does so, then
/jsonapi/node/article/UUID-OF-THAT-ARTICLE/field_related_content
returns a collection that contains the full resource objects of each node (regardless of bundle) that is referenced by that ER field.I'm unclear, however, on why that requires us to add a
/jsonapi/node
collection to the core module rather than toJSON:API Extras
. Unless there's an overwhelmingly compelling reason to do that, I'd rather for example, keep that out of the scope of what's being proposed for Drupal 8.7, and perhaps revisit adding it into Drupal 8.8 if it proves to be robust inJSON:API Extras
first.Comment #42
Wim LeersWFM.
Comment #43
e0ipsoComment #44
ndobromirov CreditAttribution: ndobromirov at FFW commented#42 what exactly do you mean there :) ? https://www.urbandictionary.com/define.php?term=wfm
I suspect
Works for me
.Is the patch in #4 valid to any extent?
Is it compliant with the latest state of the module?
Comment #45
Wim Leers#44: sorry! Yes, "WFM" = "Works For Me" :)
I very much doubt #4 still applies, it's nearly a year old.
And for the record: I think that we're still in the same place: @e0ipso still feels strongly that mixed-bundle collections should not be supported, and I think @gabesullice, @effulgentsia and I feel otherwise. A rare place of disagreement, but it hasn't been super important yet, so we've chosen to spend our time on things where we do have consensus :)
Comment #46
ndobromirov CreditAttribution: ndobromirov at FFW commentedI think a pros+const can help alleviate the decision. From what I see
Have a mixed nodes collection:
Pros:
- More developer and end user flexibility.
- I think I will need this one at some near future... :D
Cons:
- Bigger change to have performance and technical issues (complexity).
- Goes against REST principles - 1 endpoint 1 resource type.
- In context with #2145751: Introduce ENTITY_TYPE_list:BUNDLE cache tag and add it to single bundle listing will still use the node_list tag, but display much more content.
- In context with #3039730: Include paths are resolved for every resource in a resource collection, instead of once per unique resource type will need to compute and validate includes against all types listed in the collection.
That's all I can come up with at the moment...
Comment #47
mglamanPros: Drupal Commerce can properly use JSON API without custom modules for catalogs, carts,and product pages over GraphQL which supports this.
Comment #48
e0ipsoHow much of those pros would be solvable with parallel requests to the resources for the different bundles?
Comment #49
ndobromirov CreditAttribution: ndobromirov at FFW commentedIt is solvable, but inconvenient. In case of cold cache this are X bootstraps and custom merging of the results.
Comment #50
e0ipsoIn case of partial browser cache hits you may have a performance boost instead.
If multiple bootstraps are the big concern your front end client should transparently interface with Subrequests.
Comment #51
lauriiiThe use case that isn't covered by using parallel requests is when you have a list containing content from multiple bundles with sorting and pagination. This is something we need in the JavaScript & Admin UI modernization initiative for building the
/admin/content
route.Comment #52
e0ipsoThat was exactly what I was thinking @lauriii
The pros and cons of this issue should be restricted to that case. Everything else is doable (and potentially more performant with parallel requests).
Comment #53
e0ipsoIf the JS & UI Modernization initiative is the main / only use case of this I'd like to retitle this issue for that specific use case. However I suspect that @mglaman will have a need for this too.
In the mean time you can achieve this with two serial levels of requests. Is that not good enough for your needs?
Comment #54
lauriii+1 to #52. Would be nice to hear from @mglaman as well if they have some uncovered problems that aren't solved by parallel requests for different bundles.
Comment #55
bojanz CreditAttribution: bojanz at Centarro commentedParallel requests are not a solution for Commerce.
A product catalog has different bundles, just like /admin/content does.
An order is made of order items that have different bundles.
Comment #56
mglamanSo, if I wanted to build a product catalog which had products of a mixed bundle, limited to 15 products, sorted by title... how would this even work? I need to make two requests and hope all goes well? It's unfortunate since it's viable out of the box with GraphQL.
Comment #57
Wim LeersThe GraphQL module just gets this from the Entity/Field Query API. The JSON:API module uses that too and could provide this capability too. It's purely a choice not to do so: @e0ipso firmly believe that it's confusing to non-Drupal people to have mixed-bundle collections. I understand where he's coming from. I agree we should nudge people towards
/jsonapi/node/article
and/jsonapi/node/something
, not/jsonapi/node
. But if we provide/jsonapi/node
for those use cases that need it (JS admin UI & Commerce product catalog for example), I don't think that'll lead to confusion. Especially if/jsonapi
continues to point to only/jsonapi/node/article
+/jsonapi/node/something
, not/jsonapi/node
.(Also see #28 and #29.)
Comment #58
mglamanI will agree that it makes sense for the entry point
/jsonapi
would still link to specific resource type links, while the generic endpoints are available and "undocumented."Comment #59
Wim LeersExactly :)
Comment #60
e0ipsoYes, I think we are on the same page. However remember that this URL hierarchy with node/article is not semantic, just pure un enforced convention.
Comment #61
Wim LeersRight. We could do something like
/jsonapi/node/::all::
if you prefer — where we use a character that is legal in the URL path component but illegal as a Drupal entity bundle name.Comment #62
mglamanShoot, too bad we couldn't pick something friendlier, but we would need to avoid naming clashes. Can bundles start with an underscore? I think something like
/jsonapi/entity/_all
could be more palatable and also hints that it is more of a "not to be used" endpoint. Prefixing things with an underscore is across the board a pretty understood pseudo way of saying "private"Comment #63
e0ipsoIf I needed support for that today this is the way I'd implement it:
Comment #64
gabesulliceI've been trying to build a personal blog for myself and to use JSON:API for it. I have a few different content types: posts, external posts, conference talks, and albums. I'd like to list them chronologically on my homepage and to be able to filter them by tags like "Drupal" or "Aviation".
Getting those things in a "feed" of sorts is not a very confusing idea, really, even though the listing will have resources of different types.
Let's imagine that the URL for
/jsonapi/node
was/jsonapi/content
, conceptually, I think that URL would make perfect sense, even if fields varied drastically between resources. IOW, the main "Drupalism" in/jsonapi/node
is the word node, not the idea of a collection with multiple resource types. Perhaps the confusing bit is that the types are hierarchical? That's why @Wim Leers suggested/jsonapi/node/all
I think, to discourage that line of thought. We can totally ignore the fact that that bundles are an "extension" of the node entity type and still have a coherent API. Take this other hypothetical URL:/jsonapi/posts?filter[category]=photo_album
. That'd actually be a very WordPress-y URL. And conceptually,/jsonapi/posts/photo_albums
as an alias for that URL would also be handy. That's how I'd conceive of our URLs if we were to support collections entities of a single type.All of the previous paragraph is essentially arguing against the idea that we'd confuse non-Drupal developers by having a
/jsonapi/node
route and what I'm getting at is that I think it's a little patronizing for us to imagine that this would somehow be too difficult or confusing for them. IOW, on its own, this argument doesn't stand up for me. Perhaps I'm just debating a straw man though. Maybe that's not a primary motivation for not having these routes (See below about "first principles" so that we can all get on the same page).Let's do away with the suggestion that this would somehow be contrary to RESTful principles. (AFAIK, @e0ipso has never said that either). A REST resource certainly doesn't have to be of a single type.
Let's also dispell the notion that JSON:API can't support mixed-bundle collections because of deeply technical reasons. Every
related
endpoint of cardinality n>1 is already potentially a mixed bundle collection.#63 sounds extraordinarily complex and I don't understand the great complexity we're avoiding in JSON:API to create such a high bar for the use cases so far mentioned.
@e0ipso, I know that this is probably very frustrating to argue this once again. But I've never really understood your reasoning completely. It would be very useful for me to understand your position from first principles.
Comment #65
ndobromirov CreditAttribution: ndobromirov at FFW commented#64 +1.
Comment #66
e0ipsoI'm very confused by the how the conversation is going in this issue. AFAIK I have already given my +1 more than once to implement this. However it seems like other people think I'm opposed to the idea 🤔
#63 is meant to be read as: I don't have availability to work on this now, if this is super pressing here's a possible implementation with the tools you have today.
Comment #67
gabesulliceHah! This would indeed be very confusing! I think Wim and I must have misunderstood/missed/forgotten this +1. We have both been under the impression that we needed to convince you and that you were vehemently opposed to this being in JSON:API.
Comment #68
gabesulliceIt seems I missed that this issue was moved to JSON:API Extras...
I once again am confused about why this can't be in JSON:API itself.
Comment #69
e0ipsoAh, OK. I see where you are coming now.
You are arguing in #64 about the feasibility of the feature, not where we should implement it. I do feel strongly against implementing this in JSON:API directly. Maybe we can leave this issue for the discussion on how to implement this, and then have a discussion where to put this?
Comment #70
gabesulliceWFM!
Comment #71
e0ipsoA quick note about #4.
We can't rely on this because resource type names can be aliased. However it should be possible to get the entity type ID from the resource type.
Comment #72
jpschroeder CreditAttribution: jpschroeder at Braid commentedIs the discussion about where to implement this happening in another thread? We're deploying a lot of decoupled Drupal these days and are eyeing the JSON API as a great alternative to the somewhat hacky views/rest exports and custom modules we've done in the past. However, being able to do entity wide filters is keeping us from fully adopting it.
So from my company's perspective its high enough value we'd be willing to help put some engineering resources behind making this happen, but I guess the next question is – where should we start contributing? Based on the fact that @e0ipso is highly opinionated on this not being in JSON:API directly, should patches for JSON:API Extras be created?
Comment #73
mglamanI just gave this a go against Drupal 8.7.4 based on the Admin UI implementation. I got close until it came on filtering field configuration fields.
This is due to \Drupal\jsonapi\Context\FieldResolver::getFieldItemDefinitions receiving a null bundle.
Comment #74
Wim LeersThis keeps coming up. From Commerce, to @jpschroeder in #72, @gabesullice in #64, to the Drupal JS Admin UI project.
@e0ipso: Do you still feel strongly against doing this in JSON:API itself? Has your thinking evolved based on feedback from the community?
Comment #75
e0ipsoYes. The fact that it only comes out so rarely feels like a validation of my feeling: it is important to a niche of projects and worth implementing, but not in jsonapi core due.
Let's have an implementation patch first. We can discuss again where to put it once we have a clear vision of what the code looks like.
Comment #76
Wim LeersThis weekend, #3067737: Search API support in JSON:API was opened, in part because this does not exist in the JSON:API module itself.
Comment #77
e0ipsoWe discussed this in Decoupled Days 2019. We came to the following conclussions:
jsonapi_cross_bundles
GET
/jsonapi/node
that will contain: (a) a list of links to the resource types for that entity type, and (b) link to a documentation page explaining the cross bundle situation (maybe even mentioning the experimentaljsonapi_cross_bundles
module).@mglaman is already working on a
jsonapi_cross_bundles
module that will allow experimentation on this area.I belive this can be closed and continue the discussions about particular approaches there.
Comment #78
e0ipsoComment #80
geek-merlinFTR: https://www.drupal.org/project/jsonapi_cross_bundles
;-)