Problem/Motivation

As noted in #2829746: Clean up \Drupal\jsonapi\LinkManager\LinkManager(Interface) we want to simplify the link generation by creating a JSON API specific entity link.

Proposed resolution

As expressed in the linked issue:

I think \Drupal\jsonapi\LinkManager\LinkManager::getEntityLink() should not be necessary; instead the JSON API module should register a new link relation for every entity type. So that you can do $entity->toUrl('jsonapi').

Postponed by #2353611: Make it possible to link to an entity by UUID

Comments

e0ipso created an issue. See original summary.

wim leers’s picture

wim leers’s picture

Assigned: Unassigned » wim leers

Since the ability to do $entity->toUrl('jsonapi') also requires a entity.$entity_type_id.jsonapi route to exist, we'll need to take inspiration from #2293697: EntityResource POST routes all use the confusing default: use entity types' https://www.drupal.org/link-relations/create link template if available too.

wim leers’s picture

Status: Active » Needs review
StatusFileSize
new2.25 KB

Here's a rough initial version.

wim leers’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests
  1. +++ b/jsonapi.module
    @@ -33,6 +33,19 @@ function jsonapi_help($route_name, RouteMatchInterface $route_match) {
    +    $jsonapi_path = $entity_type->getBundleEntityType()
    +      ? sprintf('/jsonapi/%s/{%s}/{%s}', $entity_type->id(), $entity_type->getBundleEntityType(), $entity_type->id())
    +      : sprintf('/jsonapi/%s/%s/{%s}', $entity_type->id(), $entity_type->id(), $entity_type->id());
    

    This is correct.

  2. +++ b/src/Routing/Routes.php
    @@ -139,6 +139,9 @@ class Routes implements ContainerInjectionInterface {
    +      // Enable generating this URL by doing $entity->toUrl('jsonapi').
    +      // @see jsonapi.link_relation_types.yml
    +      $collection->add(sprintf('entity.%s.jsonapi', $resource_type->getEntityTypeId()), $route_individual);
    

    But this is not yet correct. Because a separate individual route is generated for each bundle of an entity type, this currently is using the last enumerated bundle and hardcoding that for all entities of this entity type.

    For example, for Node on a default install this will result in /jsonapi/node/page/<node ID> for all nodes, which is obviously wrong.

    IOW: this needs a different route definition.

wim leers’s picture

Note that this is already resulting in <link rel="jsonapi" href="/jsonapi/node/page/1" /> automatically being added to the HTML <head>, as well as a Link:</jsonapi/node/page/1>; rel="jsonapi" response header!

e0ipso’s picture

This is correct.

Shouldn't it be UUID?

e0ipso’s picture

Are generating 4 different link types and embedding them in our responses:

  1. Individual entities.
  2. Collection.
  3. Relationship link.
  4. Related link.

We should be able to generate them all with link relation if we want to move in this direction, otherwise it will be inconsistent. Agree?

wim leers’s picture

#7: no, that's the entity type ID, not the entity ID!

#8: Perhaps. What are the link relation names you suggest?

  1. jsonapi-individual
  2. jsonapi-collection
  3. jsonapi-relationship
  4. jsonapi-related

but… jsonapi-relationship and jsonapi-related links don't entirely make sense, because you'd need to add a URL for every related/relationship thing for that entity type + bundle! And that's something that Entity::toUrl() simply does not support: it hardcodes the assumption that for every relationship there is only one URL.

Therefore only jsonapi-individual and jsonapi-collection are ever possible. Which means that we might as well simplify it to jsonapi and jsonapi-collection.

dawehner’s picture

but… jsonapi-relationship and jsonapi-related links don't entirely make sense, because you'd need to add a URL for every related/relationship thing for that entity type + bundle! And that's something that Entity::toUrl() simply does not support: it hardcodes the assumption that for every relationship there is only one URL.

I'm wondering whether it should be possible to pass along some of the parameters using the $options parameter, if well, its optional.

wim leers’s picture

#10: I thought about that too, but that'd be violating the API, because:

  /**
   * Gets the URL object for the entity.
   *
   * The entity must have an id already. Content entities usually get their IDs
   * by saving them.
   *
   * URI templates might be set in the links array in an annotation, for
   * example:
   * @code
   * links = {
   *   "canonical" = "/node/{node}",
   *   "edit-form" = "/node/{node}/edit",
   *   "version-history" = "/node/{node}/revisions"
   * }
   * @endcode
   * or specified in a callback function set like:
   * @code
   * uri_callback = "comment_uri",
   * @endcode
   * If the path is not set in the links array, the uri_callback function is
   * used for setting the path. If this does not exist and the link relationship
   * type is canonical, the path is set using the default template:
   * entity/entityType/id.
   *
   * @param string $rel
   *   The link relationship type, for example: canonical or edit-form.
   * @param array $options
   *   See \Drupal\Core\Routing\UrlGeneratorInterface::generateFromRoute() for
   *   the available options.
   *
   * @return \Drupal\Core\Url
   *   The URL object.
   *
   * @throws \Drupal\Core\Entity\EntityMalformedException
   * @throws \Drupal\Core\Entity\Exception\UndefinedLinkTemplateException
   */
  public function toUrl($rel = 'canonical', array $options = []);
wim leers’s picture

I just stumbled upon the issue that aims to make it possible to have link relationships have multiple URLs: #2801067 — I left a comment there about this issue: #2801067-4: Link templates on entity types should support multiple links.

e0ipso’s picture

Interesting. Let's see how that evolves.

e0ipso’s picture

@Wim Leers where do you think we stand on this after the past 4 months? I know that at some point you "gave up" because of implementation difficulties. Anything new in core land that can help us?

wim leers’s picture

Assigned: wim leers » Unassigned
Status: Needs work » Needs review
StatusFileSize
new3.51 KB
new5.77 KB

Anything new in core land that can help us?

No.

In #9, I wrote:

Therefore only jsonapi-individual and jsonapi-collection are ever possible. Which means that we might as well simplify it to jsonapi and jsonapi-collection.

But the only link relationship that really matters is the individual JSON API resource. Because that is what allows the /node/1 HTML response to automatically have a

Link:</jsonapi/node/article/UUID>; rel="jsonapi"

link relationship in the response header, and from there, all other links can be followed. That's enough.

Updated patch attached, should be green.

Status: Needs review » Needs work

The last submitted patch, 15: jsonapi_link_relation_type-2878463-15.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

wim leers’s picture

Title: feat(Meta): Define a JSON API link relation for entities » [PP-1] feat(Meta): Define a JSON API link relation for entities
Status: Needs work » Postponed
+++ b/tests/src/Functional/JsonApiFunctionalTest.php
@@ -20,6 +20,11 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
+    // 0. Discoverability: verify
+    $this->drupalGet('/user/1');
+    var_dump($this->drupalGetHeader('Link'));
+    return;

I was working on integration test coverage. I didn't mean to add that to this patch.

This doesn't work yet, because #2878463: [PP-1] Define a JSON API link relation for entities is a hard blocker.

wim leers’s picture

Title: [PP-1] feat(Meta): Define a JSON API link relation for entities » feat(Meta): Define a JSON API link relation for entities
Status: Postponed » Needs work

I think the link in #17 should have been #2282029: Automate link relationship headers for all entity types, not just nodes, but I'm not sure.

I don't see why we couldn't test against only Node for now, then this wouldn't need to be blocked AFAICT.

wim leers’s picture

Status: Needs work » Needs review
Issue tags: +Routing
StatusFileSize
new1.68 KB
new6.8 KB

Let's get this going again.

  1. #2936714: Entity type definitions cannot be set as 'internal' means we should only add the jsonapi link template on non-internal entity types. Updated jsonapi_entity_type_alter() accordingly.
  2. Because #2940336: JSON API incorrectly requires the "access content" permission for *all* routes is not yet fixed, I had to grant the access content permission to be able to write an integration test.
  3. … this works kind of when manually testing as an authenticated user, but then it results in Link:</jsonapi/node/page/435>; rel="jsonapi", i.e. with the node ID rather than the node UUID.
  4. … this fails when testing as an anonymous user, because then $url->access($this->currentUser) is called, which results in the route being constructed, but that fails because the provided parameter is the node ID, which \Drupal\jsonapi\ParamConverter\EntityUuidConverter::convert() doesn't know how to convert, nor does it want to. The problem, in other words, is the {node} route parameter that is firmly associated with the ID, not the UUID. We need something like {node:uuid}. That'd also solve the problem described in the previous bullet.

I think we might need a routing system expert for this.

dawehner’s picture

There is a similar core issue for 4. isn't it? (#2353611: Make it possible to link to an entity by UUID). It wouldn't work in the current state, but we could check for something like node:uuid or so instead. I suggested a small change of direction for that issue, so we can maybe make more progress over there.

wim leers’s picture

Yep, I was contemplating linking to that issue, but didn't have the time to dig into the status/scope of #2353611, so thank you for doing that! ❤️

wim leers’s picture

Title: feat(Meta): Define a JSON API link relation for entities » [PP-1] feat(Meta): Define a JSON API link relation for entities
Status: Needs review » Postponed

Let's make it clear that this is hard-blocked on #2353611. Posted #2353611-191: Make it possible to link to an entity by UUID to make that clear in the blocking issue too.

wim leers’s picture

Version: 8.x-1.x-dev » 8.x-2.x-dev

2.x will require >=8.5. Hence 1.x will never be able to do this.

wim leers’s picture

Title: [PP-1] feat(Meta): Define a JSON API link relation for entities » [PP-1] Define a JSON API link relation for entities
Project: JSON:API » Drupal core
Version: 8.x-2.x-dev » 8.9.x-dev
Component: Code » jsonapi.module
Issue tags: +API-First Initiative

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

bbrala’s picture

Issue summary: View changes

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.