Problem/Motivation

Impossible to include the paragraphs for the preview.

Steps to reproduce

Install the paragraph module.
Configure a node with paragraphs.
Create a content with paragraphs, then click on "preview".
Access the preview endpoint on the JSON API.

Comments

Elendev created an issue. See original summary.

elendev’s picture

I've found the issue: it's an access check linked to the fact that the permission `view all revisions` is only applied to node and media.
Line 198 - 199 of EntityAccessChecker.php: https://api.drupal.org/api/drupal/core%21modules%21jsonapi%21src%21Acces...

  protected function checkRevisionViewAccess(EntityInterface $entity, AccountInterface $account) {
    assert($entity instanceof RevisionableInterface);
    assert(!$entity->isDefaultRevision(), 'It is not necessary to check revision access when the entity is the default revision.');
    $entity_type = $entity->getEntityType();
    switch ($entity_type->id()) {
      case 'node':
      case 'media':
        $access = $entity->access('view all revisions', $account, TRUE);
        break;

      default:
        $reason = 'Only node and media revisions are supported by JSON:API.';
        $reason .= ' For context, see https://www.drupal.org/project/drupal/issues/2992833#comment-12818258.';
        $reason .= ' To contribute, see https://www.drupal.org/project/drupal/issues/2350939 and https://www.drupal.org/project/drupal/issues/2809177.';
        $access = AccessResult::neutral($reason);

Bypassing this permission fixes this issue.

To bypass this permission, one can create a custom module and extend the EntityAccessChecker of JSONAPI:


namespace Drupal\my_module\Access;

use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\jsonapi\Access\EntityAccessChecker as EntityAccessCheckerBase;

/**
 * Override the default EntityAccessChecker to allow access to a wider range of
 * entity types.
 * @see https://www.drupal.org/project/jsonapi_node_preview/issues/3268796
 */
class EntityAccessChecker extends EntityAccessCheckerBase {

  protected function checkRevisionViewAccess(EntityInterface $entity, AccountInterface $account) {
    $access = parent::checkRevisionViewAccess($entity, $account);

    // Keep the logic of the original method, but make an exception for paragraph, as we need to use it
    // for the preview in the jsonapi_node_preview module.
    if ($entity->getEntityTypeId() === 'paragraph') {
      $access = $access->orIf($entity->access('view all revisions', $account, TRUE));
    }

    return $access;
  }

}

And register it as a decorator service in my_module.services.yml:

services:
  my_module.jsonapi_entity_access_checker:
    class: Drupal\my_module\Access\EntityAccessChecker
    public: false
    decorates: jsonapi.entity_access_checker
    # Based on core/modules/jsonapi/jsonapi.services.yml, lines 154-165
    arguments: ['@jsonapi.resource_type.repository', '@router.no_access_checks', '@current_user', '@entity.repository']
    calls:
      - [setLatestRevisionCheck, ['@?access_check.latest_revision']] # This is only injected when the service is available.
albertosilva’s picture

Hi @elendev:

I think you are trying to get a node preview from a non-default revision, passing also an include parameter to get that Paragraph. Using a non-default revision makes JSON:API call checkRevisionViewAccess() with that Paragraph entity as an argument, making JSON:API throw an error.

Using a node's default revision works as expected.

From my point of view, this is a problem/bug with JSON:API, where using a non-default revision for an entity enforces having to use that revision for all other included entities, even though they are not revisionable.

Thanks for sharing a solution for this problem, but there is nothing I can do as a module maintainer to fix it, since it is outside of the scope of JSON:API Node Preview.

Thanks!

albertosilva’s picture

Status: Active » Closed (works as designed)