From the "path to core" issue, we need to:
- Document architecture + what the PHP API is + what the HTTP API is
- Re-analyze codebase to make as much as possible @internal
We've already gotten a start on this with the addition of jsonapi.api.php by #2860350: Document why JSON API only supports @DataType-level normalizers.
However, we should take a closer, more holistic look at the module here (not just focused on normalizers) and very precisely document our API guarantees.
We then need to take a fine-toothed comb to every class, interface, hook and service to ensure that they are properly documented and marked as @internal.
Comments
Comment #2
gabesulliceThe attached patch further clarifies the intent of some of our design decisions and clarifies the scope of the module API.
@e0ispo, please pay special attention to the changes I made to the normalizer docs.
Comment #3
gabesulliceFiles not marked as @internal (excluding test classes):
ResourceTypeandLinkManagerare both explicitly marked with@api. Do we want that?From Slack:
gabesullice [1:06 PM]e0ipso [1:08 PM]gabesullice [1:12 PM]Comment #4
wim leers"specification (the spec)" looks weird to my eyes?
s/is committed/module is committed/
Nice!
This can be misinterpreted, the current text is clearer.
Excellent addition!
"derives" is confusing in this context IMHO. "expose" would be clearer.
"entity type + bundle as a resource type" -> this is clearer, perhaps you can phrase it like this above as well?
"DataType" plugin levelAlso: it's not a risk, it's a certainty.
will
Nit: I think "zero configuration" is clearer.
While we're clarifying this anyway: s/fields/field types/
to generate a JSON API representation of an entity
Comment #5
wim leers#3:
EntityToJsonApiclass should be marked@api.@internal.@internal.@internal.ResourceType,LinkManagerandResourceTypeRepositoryInterfaceshould all be@internal. Just because something is necessary forjsonapi_extras(which itself is highly in flux) doesn't mean that it should be a public API that the JSON API module commits to supporting, let alone that Drupal core will commit to supporting. Especially because there's only a single consumer. Like Gabe, I think that it should be up to the JSON API Extras module to stay in sync. This doesn't mean we'll make just any change — we should make sure that JSON API Extras doesn't break horribly, so that JSON API Extras can support the current core minor and the previous core minor. But making it an actual API not only is a maintainability risk, it also limits JSON API Extras in the future. Because, effectively, this is an "API" only to allow the JSON API Extras module to cleanly do its thing. But once JSON API is in core, other modules might start depending on it too, and then we won't be able to make changes just to accommodate JSON API Extras anymore. This strategy can work fine: I used it in https://www.drupal.org/project/big_pipe_sessionless too. To enable that module, I refactored core's BigPipe code to allow the BigPipe Sessionless module to reuse maximally, and inject extra logic in just the right places. But there is no official API that the BigPipe module maintains. The burden is on me, maintainer of https://www.drupal.org/project/big_pipe_sessionless, to keep it in sync. And that's totally doable :)Comment #6
e0ipsoIf we do that it means that no one but JSON API Extras can make use of what it's now marked as
@apimoving forward. I can accept that, but I'd like to see that reflected in the docs here.Also, this will be a breaking change. Let's cut
jsonapi-8.x-2.x.Comment #7
wim leers+1, this needs to be documented of course.
What if we just mark those things that are currently
@apibut are becoming@internalas@deprecated? Then it's a deprecated API, and everything remains as-is. When JSON API moves into core, the deprecation takes effect. Result: existing users relying on this (likely VERY few) are not disrupted but are warned, and when it moves into core, it comes into effect. Thoughts?Comment #8
e0ipsoI have no strong feelings about #7. We'd be making a new major version when moving into core then. Which is fine by me, but I think it keeps us more honest if we do it as soon as possible.
Comment #9
gabesulliceI don't like writing "the spec", this made me feel better about it. I think I'll just get rid of the shortening elsewhere.
Thanks, I was not sure about that.
The attached patch only has verbiage changes. It doesn't have any of the changes from #3 or #5.
Comment #10
gabesulliceBah, forgot the patch.
Comment #11
e0ipsoPlease make sure to also include the changes requested in #6.
Comment #12
gabesulliceThe attached marks all classes as
internal, except for:EntityToJsonApi, which was explicitly marked as@internalResourceType*, which were marked as@deprecatedLinkManager, which was marked as@deprecatedThis calls for a special release note:
I'm unclear why the
LinkManagerwas ever marked as@api, so I'm not sure how to word a release note for that. What features would we be foregoing there?Comment #13
e0ipso@gabesullice as noted in #2857730-10: Add a link to get only published entities in collections I think that true HATEOAS needs to populate links from within the application (it's not possible to do it from the module itself).
The link manager is the service the actual sites will use to create those links properly.
That poses the question of: are we sure we want to remove it?
Comment #14
gabesulliceThanks for the context @e0ipso. I wasn't sure what the use case would be. It makes sense that applications should be able to add/remove link relations... but we really aren't exposing that as an API here. Given the methods on this class, it looks like we're really only letting a hypothetical consumer of this API change the
selfand pagination links... which are very closely coupled to the rest of our implementation.If we actually had an interface like
JsonApiLinkProviderInterface::getResourceLinks(): LinkInterfaceandLinkInterface::getRel(): stringandLinkInterface::getUrl(): Urlthen my opinion would be different.So, given the very limited usefulness of this API and the high degree of coupling to our implementation, my preference would be to deprecate this and make a follow-up to implement a more HATEOS friendly API.
Comment #15
wim leers#10: 👍
#12:
Hm, I think we should keep
@apiand add@deprecated?Aren't tests always
@internal? I guess it doesn't hurt to be very explicit.#13 + #14: I sort of agree with both of you on that one :D I agree with @e0ipso that it should be possible to define additional links on resources. But at the same time, I agree with @gabesullice about
LinkManagernot really qualifying as an API. Apparently #2907123: Mark LinkGenerator and ResourceType as API classes markedLinkManageras@api. The justification there was — which is not quite correct. The correct way is to get the URL for thejsonapi.entityType--bundle.individualroute. That's not very practical though. So the next best way to get that URL is to do something like\Drupal::service('jsonapi.entity.to_jsonapi')->normalize($entity)['data']['links']['self']. But the real solution would be #2878463: [PP-1] Define a JSON API link relation for entities.Which is why I agree that
LinkManagershould be marked@deprecated: not only is usingLinkManager::getEntityLink()a hard-to-find API to get a URL for an entity (for that we have$entity->toUrl('some-link-relation-type'), more importantly,LinkManageritself is not extensible: it's impossible to define additional links to be added, due to its design.Comment #16
wim leersIMHO this is ready. @e0ipso should be the one to do final review and commit this.
Comment #17
e0ipsoYeah, @gabesullice is right about
LinkManager. I was speaking about what I hoped it had become through iterations and support requests that never happened. That indicates that people don't care about links or HATEOAS, which makes me a bit sad. But it's a reality I embrace by making it an internal API.For the record, I think #2878463: [PP-1] Define a JSON API link relation for entities will be a step forward, but not enough. I may want to add a link to the collection of line items in stock inside of the JSON API representation of the shopping cart (aka a link to a collection with filters and all the fanfare)… but one step at a time.
I will be merging this soon as is. Thanks for all the work and discussions.
Comment #18
wim leersYep (hope/aspirations), yep (sad reality) and yep (embracing sad reality).
That's interesting :) It'll be hard to provide a simple/generic API for this. "Get the URL for the individual JSON API representation of this entity" is simple. "Get this particular set of entities meeting a particular set of conditions" is complex. That'll be an interesting challenge :) I suspect that it'll become clearer how we can/should achieve that as we gain more real-world experience and examples.
➕
Comment #19
e0ipsoCommitted!