Problem/Motivation

See #2829977: SerializableHttpException and Drupal\jsonapi\Error\* are not necessary, specifically #2829977-25: SerializableHttpException and Drupal\jsonapi\Error\* are not necessary. The most relevant info of that issue:

We had the same problem in the REST module, and we fixed that in #2807501: ResourceResponse::$responseData is serialized, but is never used: unserializing it on every Page Cache hit is a huge performance penalty. We want the exact same solution here. Then there is no need for a __sleep() method. Yes, that means we're duplicating code from the REST module. But better a duplication than an incorrect abstraction. If it turns out that it's the right abstraction, we can move the code for this over to the Serialization module. So that still leaves open the door for future simplification. For now, what matters is that we follow the exact same pattern.

In other words: we should revert the changes made by #2818221: [BUGFIX] Restore serialization with HttpException inline responses and instead introducing the same solution that is used in core's rest module: #2807501: ResourceResponse::$responseData is serialized, but is never used: unserializing it on every Page Cache hit is a huge performance penalty. Opened #2855693: Remove \Drupal\jsonapi\Controller\RequestHandler::renderJsonApiResponse(), add \Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber for that, because tacking that onto this issue will make this issue/patch very very difficult to review.

Postponed on #2829977: SerializableHttpException and Drupal\jsonapi\Error\* are not necessary, which is postponed on #2841027: JSON API format should only be used on JSON API routes, but can currently also be used for REST resources.

Proposed resolution

  1. Remove \Drupal\jsonapi\Controller\RequestHandler::renderJsonApiResponse()
  2. Add ResourceResponseSubscriber
  3. Add explicit test coverage proving it works correctly with Dynamic Page Cache

Remaining tasks

None.

User interface changes

None.

API changes

None.

Data model changes

None.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Wim Leers created an issue. See original summary.

Wim Leers’s picture

\Drupal\Tests\jsonapi\Kernel\Controller\RequestHandlerTest's only purpose is testing the automatic validation of JSON API responses against JSON API's JSON schema. That code now lives in \Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber. That still needs to be moved.

Wim Leers’s picture

Title: [PP-2] Remove \Drupal\jsonapi\Controller\RequestHandler::renderJsonApiResponse(), add \Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber » [PP-1] Remove \Drupal\jsonapi\Controller\RequestHandler::renderJsonApiResponse(), add \Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber
Wim Leers’s picture

e0ipso’s picture

Title: [PP-1] Remove \Drupal\jsonapi\Controller\RequestHandler::renderJsonApiResponse(), add \Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber » Remove \Drupal\jsonapi\Controller\RequestHandler::renderJsonApiResponse(), add \Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber
Status: Postponed » Needs review

Status: Needs review » Needs work

The last submitted patch, 3: 2855693-3.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
FileSize
15.12 KB

Here is a reroll.

Status: Needs review » Needs work

The last submitted patch, 8: 2855693-8.patch, failed testing.

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
1.83 KB
15.46 KB

I'm afraid the rebase in #8 wasn't entirely correct. Thanks though :)

I think this one is.

dawehner’s picture

Thank you wim!

Status: Needs review » Needs work

The last submitted patch, 10: 2855693-10.patch, failed testing.

Wim Leers’s picture

Apparently not enough yet. On it.

Wim Leers’s picture

Assigned: Wim Leers » Unassigned
Status: Needs work » Needs review
FileSize
4.28 KB
15.37 KB

Oh hah. #2857658: Get rid of ResourceResponseInterface is what's causing these 5 failures :) A very silly reroll. Removed all 6 occurrences.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Ha, so we have test coverage for that. Good to know

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 14: 2855693-14.patch, failed testing.

Wim Leers’s picture

Assigned: Unassigned » Wim Leers
Status: Needs work » Needs review
FileSize
1018 bytes
15.37 KB
  1. I can't reproduce the failure in RestJsonApiUnsupported (and its duplicate, RestJsonApiFormatUnsupported).
  2. Fixed the failures in JsonApiFunctionalTest and JsonApiFunctionalMultilingualTest.
  3. I totally forgot about the failures in \Drupal\Tests\jsonapi\Kernel\Controller\RequestHandlerTest — despite me writing in #3 that that test coverage also still needed to be moved. Working on that now.
Wim Leers’s picture

Fixed #17.3:

  1. Converted the kernel test to a unit test.
  2. This required me to refactor away the use of DRUPAL_ROOT.
  3. This also required me to refactor away the reliance on the container (by using \Drupal::logger()).
  4. #2840677: Validate responses against the JSON API specification uses the logger.channel.jsonapi service yet does not define it. IOW: test coverage for the logging itself is missing. Not fixing that here, just adding the service, because I need it.

The last submitted patch, 17: 2855693-17.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 18: 2855693-18.patch, failed testing.

Wim Leers’s picture

100% of the remaining failures are now:

  1. I can't reproduce the failure in RestJsonApiUnsupported (and its duplicate, RestJsonApiFormatUnsupported).

I was finally able to reproduce this! #2844046: REST Resource config entities do not respect the status (enabled/disabled) is causing this. It changed some test internals. This fixes it.

dawehner’s picture

  1. +++ b/src/EventSubscriber/ResourceResponseSubscriber.php
    @@ -0,0 +1,214 @@
    +
    +    assert('$this->validateResponse($event->getResponse())', 'A JSON API response failed validation (see the logs for details). Please report this in the issue queue on drupal.org');
    ...
    +   */
    +  protected function validateResponse(Response $response) {
    +    if (!class_exists("\\JsonSchema\\Validator")) {
    

    As an additional follow up this could be moved into its own subscriber

  2. +++ b/src/EventSubscriber/ResourceResponseSubscriber.php
    @@ -0,0 +1,214 @@
    +    $schema_path = dirname(dirname(__DIR__)) .'/schema.json';
    

    +1 for that. ALternative you could have injected the app root

Wim Leers’s picture

  1. I'd like that. But it'll be harder to detect whether this is a JSON API response in a separate response subscriber. But yes, matter for a separate issue.
  2. That would not have worked, because the JSON API module can be installed in many locations. And drupal_get_path() also calls out to the container. So then a unit test would have to mock the container. This is simpler.

Do we have a RTBC? :)

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

I have one :)

e0ipso’s picture

But it'll be harder to detect whether this is a JSON API response

We have the request object in the response object. In the request object we have the route object. In the route object we have an attribute saying if the route is JSON API or not. More complex to describe than the actual code.

Responses to JSON API routes can be assumed to need schema validation (if assertions are enabled).

Can we create a follow up ticket to move the assertion to an onResponse subscriber?

e0ipso’s picture

Status: Reviewed & tested by the community » Fixed

  • e0ipso committed aeeaefe on 8.x-1.x authored by Wim Leers
    fix(Maintainability): Remove \Drupal\jsonapi\Controller\RequestHandler::...
Wim Leers’s picture

Thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.