[META] Start creating the public PHP API of the JSON:API module

Created on 13 February 2019, almost 6 years ago
Updated 27 September 2024, 2 months ago

jsonapi.api.php currently says:

The JSON:API module provides *no PHP API to modify its behavior.*...This means that this module's implementation details are entirely free to change at any time.

And correspondingly, every class and interface are marked @internal.

However, I don't think that's tenable. We know there are use-cases for wanting to customize something. For example, renaming a field from its internal Drupal name to something friendlier (e.g., "uid" to "author"). That is currently supported by ResourceType::getPublicName(). I think that's an example of something we should expose to a non-internal API (whether by creating a ResourceTypeInterface, or via some other way).

Let's use this issue to collect other examples and spin-off child issues as needed.

Public PHP APIs shipped

  1. Drupal 8.8: #3037039: Create a public API for indicating resource types should not be exposed
  2. Drupal 8.8: #3085035: Add a public API for aliasing and disabling JSON:API resource type fields
  3. Drupal 9.3: #3105318: Add a public API for aliasing resource type names
  4. Drupal 10.4 & 11.1: Method to enable a resource type field disabled by a previous ResourceTypeBuildEvent subscriber RTBC

Public PHP APIs proposed

  1. Allow specifying `meta` data on JSON:API objects Needs work
  2. Allow to include a total count of items to collection responses Needs work
  3. Increase max pager size, ideally per resource type Active
  4. #3233410: Add methods to set locatable, mutable flags in ResourceTypeBuildEvent
  5. 📌 API for JSON:API specific "extra" fields, e.g. for entity labels Active

Document public API

  1. #3222364: [JSON:API] Document ResourceTypeBuildEvent
🌱 Plan
Status

Active

Version

11.0 🔥

Component

jsonapi.module

Created by

🇺🇸United States effulgentsia

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
  • 🇳🇿New Zealand jonathan_hunt

    Further to #3100732: Allow specifying metadata on JSON:API objects, there doesn't seem to be a method to inject a meta member (https://jsonapi.org/format/#document-meta) at the top level of an API response. Should there be a new issue to address that? My use case is to expose overall content licence and site api version data, independent of the jsonapi version.

  • 🇳🇱Netherlands bbrala Netherlands

    Yeah that should be a new issue.

  • 🇬🇧United Kingdom lind101

    Not sure if this is the right place for this (please point me in the right direction if there is a more useful place), but just thought I'd drop in a few things that I'm struggling with while developing an API over the last few weeks. These mainly revolving around the extensibility of core JSON:API services due to method access modifiers (predominantly the EntityResource controller class).

    What lead me here is I wanted to try and re-use the core code in EntityResource::getJsonApiParams() and EntityResource::getCollectionQuery() in a Custom Resource by calling these methods, but couldn't because they have protected access, I then went down a rabbit hole...

    For context I'm creating a few Custom endpoints using the JSON:API Resource module with JSON:API Extras installed to enable me to easily alias resources and provide defaults, and JSON:API Include allowing me to provide a cleaner response for the consumer in certain scenarios. Quite the module cocktail!

    All of these modules are great and have worked OOB. However a lot of the time they have needed to modify a core JSON:API service, add a "shim" service or create a new service that extend an existing one etc. The main reason for this is to allow them to extend protected methods on the base service. Trying to build on-top of this very tricky when developing a module to extend the core features as you now have to be aware that popular modules (I imagine JSON:API Extras is pretty much a standard) are rolling their own instances of core services so you cannot reliably extend them yourself.

    For example jsonapi_defaults part of JSON:API Extras replaces the class used for the jsonapi.entity_resource allowing them to add default parameters in the protected getJsonApiParams method. Had the getJsonApiParams been public the same could have been achieved with a service decorator, which would then allow other modules to add decorators as well without having to know what other modules are trying to extend these services. As it stands, if I want to extend some functionality to `getJsonApiParams` and retain the functionality provided by jsonapi_defaults, I have to include the jsonapi_defaults module as a dependency and extend that class.

    As the module ecosystem around JSON:API grows, this is going to a bit of a blocker. Apologies if I don't have the back-story to the method access on these services (I'm sure there is a good reason)!

    My two cents (for what it's worth) on things that might help the DX around extending JSON:API:

    1. Merge functionality offered by JSON:API Extras into core?
    2. Open up method access on core services. Allowing useful things like:
      1. $params = \Drupal::service(Routes::CONTROLLER_SERVICE_NAME)->getJsonApiParams(Request $request, $resource_type);
      2. $query = \Drupal::service(Routes::CONTROLLER_SERVICE_NAME)->getCollectionQuery($resource_type, $params, $cacheability);
    3. EntityResource controller is doing too much IMO
      1. Filter parsing logic could be broken out into a separate public service? This could then be easily extended by decorators.
      2. Query building logic could be broken out into a separate public service? This could then be easily extended by decorators.
      3. Response building logic could be broken out into a separate public service? This could then be easily extended by decorators.
      4. Triggering some events during the execution of all of the above steps might also be an easier way to open it up slightly?

    Hopefully that's a useful view of working with the module and it's ecosystem (which is ace btw) and might help a bit with moving it forward. For now I'll build my new features specifically for the application in question as I know what the dependency tree is and can extend the relevant classes.

    Cheers! 🤟

Production build 0.71.5 2024