Problem/Motivation

JSON:API has a soft dependency on justinrainbow/json-schema; validation is performed automatically if the dependency is enabled via a check in \Drupal\jsonapi\EventSubscriber\ResourceResponseValidator:

use JsonSchema\Validator;
...
    elseif (class_exists(Validator::class)) {
      $this->validator = new Validator();
    }

@larowlan has previously noted that this causes severe performance issues at runtime, and the fix is to uninstall the dependency.

However, Experience Builder uses justinrainbow/json-schema at runtime (although at the time of writing this is not explicitly declared): #3469516: Declare explicit runtime dependency on `justinrainbow/json-schema`

In turn this will cause performance issues on sites that want to use both Experience Builder and JSON:API.

Steps to reproduce

Proposed resolution

Move ResourceResponseValidator behind some kind of feature flag instead of magically enabling it when the dependency is present. This could be a development mode flag similar to the Twig debug mode, or a feature flag module.

It may even be preferable to move this out of core to a contrib module, as this doesn't feel like it is necessarily in the core use case. Tagging for product manager review. see #2. Also I (bbrala) dont think we should remove it right now.

Remaining tasks

  1. Discuss the best solution
  2. Implement.

User interface changes

n.a.

Introduced terminology

n.a.

API changes

New feature flag module jsonapi_response_validator.

Data model changes

n.a.

Release notes snippet

JSON:API response validation has been moved to a separate module as it can affect performance. If you are developing against JSON:API and want to ensure that all responses are correctly formed, install the jsonapi_response_validator module. Otherwise, you should leave this module uninstalled.

Issue fork drupal-3472008

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

longwave created an issue. See original summary.

longwave’s picture

Actually given that this is purely a developer-facing feature I am not even sure this is a product manager decision, removing the tag again.

wim leers’s picture

Issue tags: +Performance

Quoting @larowlan:

FYI if we make this a production requirement, we should add a hook_requirements warning people with jsonapi module and assertions enabled that their performance will go through the floor because of that module's response validator.

I've been asked to audit sites for performance and found that combo in production 😱

#3469516-4: Declare explicit runtime dependency on `justinrainbow/json-schema`


As a JSON:API maintainer: +1 for this.

bbrala’s picture

Hmm, automatic discovery is kinda unsettling indeed. I agree that needs to go. I wonder if we will make things less stable if we stop validating. Especially in tests thi has merit. Altough, if performance on this is very bad (have not seem any numbers in the parent) we might want to choose and disable in anyways.

I do kinda agree on ussing a flag perhaps as twig, seems reasonable. Wonder though if we need to change ci then also to enable that. Something like parameters.jsonapi.validate_schema comes to mind then.

In order to be able to move forwards relatively quicky, this could first just be a parameter defaulting to false if not passed. Then we can consider (and perhaps implement) developer mode in a follow up.

In other news; I was also thinking if this would mean problems in #3031367: Generate JSON schema for content entity types but i think that is all fine.

bbrala’s picture

Wondering, would this same issue exist for:

Drupal\Core\Theme\Component\ComponentValidator

That kinda does the same.

  /**
   * Sets the validator service if available.
   */
  public function setValidator(?Validator $validator = NULL): void {
    if ($validator) {
      $this->validator = $validator;
      return;
    }
    if (class_exists(Validator::class)) {
      $this->validator = new Validator();
    }
  }

bbrala’s picture

Test run results. Kinda weary to do a full conclusion since variance is so high.

Run analytics timeing of step_script Disable 1 Disable 2 Enable 1 Enable 2
🖱️️️ PHPUnit Functional Javascript 1/3 03:50 02:49 04:03 03:33
🖱️️️ PHPUnit Functional Javascript 2/3 03:49 03:29 04:12 03:58
🖱️️️ PHPUnit Functional Javascript 3/3 02:56 02:38 04:03 03:12
🌐️️ PHPUnit Functional 1/8 03:32 02:52 04:29 03:54
🌐️️ PHPUnit Functional 2/8 03:41 02:42 04:10 02:36
🌐️️ PHPUnit Functional 3/8 03:36 03:21 05:22 02:44
🌐️️ PHPUnit Functional 4/8 03:05 03:11 04:20 02:56
🌐️️ PHPUnit Functional 5/8 03:38 02:47 03:27 03:37
🌐️️ PHPUnit Functional 6/8 02:59 03:20 04:22 03:43
🌐️️ PHPUnit Functional 7/8 02:42 02:33 03:59 03:24
🌐️️ PHPUnit Functional 8/8 02:45 02:45 04:56 03:06
Total time taken in functional _36:33 _32:27 _47:23 _36:43

So question then becomes. Do we really want this, or perhaps only enable this in testing for a specific node?

bbrala’s picture

Think this should fail since the validation is off by default now. Lets see if that is the case.

bbrala’s picture

Ok it seems we only have unittests for the code. That is fine, i did a booboo on the unit test arguments though, so lets fix that. Validation should be disbled by default now at least.

bbrala’s picture

Status: Active » Needs review
Issue tags: +Barcelona2024

Think this is fine, first time doing a pattern like this, so not sure if this is the right way.

Adding the extra contructor argument shoiuld be fine. We could also do this without a default value if preferred, but this way chances of breaking something seem smaller.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs change record

Code change looks fine but since it's adding a default service probably needs a change record. Maybe release notes? not 100% on the second.

bbrala’s picture

Status: Needs work » Needs review
Issue tags: -Needs change record
bbrala’s picture

Rebased and small tweak to test method order and comment. All ready.

bbrala’s picture

Issue summary: View changes
smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Thanks!

CR reads well to me, clearly defines the need and code example makes it look clean.

Ran test-only feature

1) Drupal\Tests\jsonapi\Unit\EventSubscriber\ResourceResponseValidatorTest::testValidateResponse with data set #5 (Symfony\Component\HttpFoundation\Request Object (...), Drupal\rest\ResourceResponse Object (...), true, 'Response validation disabled ...valid.', false)
Response validation disabled doesn't flags empty array as invalid.
Failed asserting that false is identical to true.
/builds/issue/drupal-3472008/core/modules/jsonapi/tests/src/Unit/EventSubscriber/ResourceResponseValidatorTest.php:81
FAILURES!
Tests: 6, Assertions: 6, Failures: 1.
Exiting with EXIT_CODE=1

Which shows coverage.

Rest of the code looks good and believe this is good to go.

longwave’s picture

Status: Reviewed & tested by the community » Needs work

Added a question about the new container parameter.

bbrala’s picture

Fair point. Will do

longwave’s picture

I'm also assuming that this can then be overridden still in a services.local.yml, but haven't checked - we should update the change record to tell people how to reenable the feature.

sumit saini made their first commit to this issue’s fork.

sumit saini’s picture

Added changes as per #17. Also, fixed flag name mismatch in files.
For #19, I have tested and confirm that it is possible to override this container parameter in services.local.yml with these changes.

wim leers’s picture

Title: Move JSON:API validation to a feature flag or separate module » Assertions + JSON:API validation in prod = poor performance, warn about this in status report
Related issues: +#3365985: Promote justinrainbow/json-schema from dev-dependency to full dependency

#3365985: Promote justinrainbow/json-schema from dev-dependency to full dependency is in.

@catch made an interesting remark over at #3365985-22: Promote justinrainbow/json-schema from dev-dependency to full dependency:

Asserts should be off in production anyway? Maybe we can add a generic status report warning for them when 'dev mode' isn't enabled?

IMHO we should instead pivot this issue to generating such a status report warning instead.

Which … coincidentally is also what @larowlan wrote, see my quote from him in #4!

So: being bold and proposing a rescope of this issue 😇 WDYT?

bbrala’s picture

Sounds like a plan to rescope. +1

anybody made their first commit to this issue’s fork.

anybody’s picture

We just ran into a case where it would have been great to have this to disable response validation. I rebased the MR.
The change record looks correct already?

anybody’s picture

Ugly hotfix attached to entirely disable JSON:API response validation until this is fixed (MR!13739).
I'll now mark that one as draft to delete once we have a working solution here.

catch’s picture

Priority: Normal » Critical

I just noticed SDC validation in the theme system, which is behind an assert.

However, the JSON:API validation is not behind an assert at all, so I don't see how this can be fixed with a status report check - bumping to critical.

bbrala’s picture

I'll put this on my list since it got bumped.

bbrala’s picture

Status: Needs work » Needs review
Issue tags: -Needs change record updates

Rebased, updated the change record.

I think we should do the implemntation as is. Allow enabling it through the parameter. Confirmed this in slack with Catch.

Tests are now green, think this is all good now :)

bbrala’s picture

catch’s picture

MR looks good to me. Only question is do we need to put this in default.services.yml or whatever the recommended dev services.yml docs are?

bbrala’s picture

I was looking around and didnt see many examples of this. But it could be added in developement.services.yml, this could mean it's at least exposed to developers.

It also almost feels like we might as well remove it it this state, who is gonna use this really ever if we hide it away. Also right now it is not even used in testing or anything (which will help speed, but might mean we slip though invalid json).

So i guess if we are to keep it, we need be complete about is and document it, and make sure it is enabled in tests.

(hmm, not making this easier, sorry ;p)

catch’s picture

Title: Assertions + JSON:API validation in prod = poor performance, warn about this in status report » Avoid JSON:API schema validation by default
bbrala’s picture

Small addendum;

core/modules/jsonapi/tests/src/Kernel/Normalizer/JsonApiTopLevelResourceNormalizerTest.php

that test does check schema's, but with code in the test. So schema's are tested.

longwave’s picture

Re #33 I am not sure I elaborated on this anywhere other than the IS but this is why I thought perhaps it should become a feature flag module; that way we can easily enable it in tests or if we decide to get rid of it we can move it out to contrib.

bbrala’s picture

That could be a way also yeah.

Which would be pretty small it seems, just add the event (and the test i guess) and enable it in jsonapi tests.

bbrala’s picture

That would mean BC break probably though right, since we'd move classes around and change the namespace. :(

That would complicate things

bbrala’s picture

seems we can do this withouth needing BC since its a subscriber.

longwave’s picture

I think we could just move ResourceResponseValidator to a submodule? Quoting the BC policy:

Class implementations and service names of paramconverters, access checkers, event subscribers and similar services which are never expected to be used directly either as services or value objects, are not considered part of the API.

We would still likely need to do this in a minor release whatever we do here, and we've missed the window for 11.3.0 now.

bbrala’s picture

Too bad about the window, but things happen. Made a new MR to move to a submodule and enabled that in the tests.

longwave’s picture

Thanks, this looks quite neat, didn't realise it would be quite so simple this way.

I think however we need a requirements hook so the module won't install if the validator library isn't available, otherwise it's not doing what it says it will do?

catch’s picture

Isn't it always available after #3365985: Promote justinrainbow/json-schema from dev-dependency to full dependency? That was why I bumped this issue to critical.

bbrala’s picture

Yeah that is the point indeed as catch mentioned. Also; the module would allow you to set a validator to use to validate a request if you use setValidator.

bbrala’s picture

Status: Needs review » Needs work
longwave’s picture

In which case this is always true I guess

    elseif (class_exists(Validator::class)) {

although we could simplify in a followup - there are also PHPStan/typehint issues which I'm on the fence about fixing here.

bbrala’s picture

Status: Needs work » Needs review

Might as well start to clean up a bit if we are not constraint by BC.

bbrala’s picture

Small fix since docblocks were wrong. Fun.

bbrala’s picture

Fun depreaction notice. We support 5 and 6 in core. So this deprecated call is needed.

 ------ ----------------------------------------------------------------------- 
  Line   core/modules/jsonapi/modules/jsonapi_response_validator/src/EventSubs  
         criber/ResourceResponseValidator.php                                   
 ------ ----------------------------------------------------------------------- 
  133    Call to deprecated method check() of class JsonSchema\Validator:       
         since 6.0.0, use Validator::validate() instead, to be removed in 7.0   
         🪪  method.deprecated 
nicxvan’s picture

You can add it to the globally ignored deprecations .deprecation-ignore.txt

longwave’s picture

Not sure we should ignore globally, because other users of the validator probably should be notified of the deprecation? We can use @phpstan-ignore in the place where we do call it though, and add a @todo to fix when we drop v5 support.

bbrala’s picture

longwave’s picture

Issue summary: View changes

Updated IS, couple of questions on the MR still but shouldn't stop anyone else reviewing.

catch’s picture

I think the SDC issue is #3352063: Allow schema references in Single Directory Component prop schemas which is RTBC but not committed yet (I haven't reviewed it yet so don't know how RTBC).

bbrala’s picture

Title: Avoid JSON:API schema validation by default » Avoid JSON:API schema validation by default when assert is enabled
bbrala’s picture

Moved some code around to clean up, and I'm questioning the critical prio, still. Good cleanup with more explicit sideeffects.

longwave’s picture

Status: Needs review » Needs work

Not sure the event subscriber actually works at present - we unit test it but do we need an integration test?

longwave’s picture

Also do we want to remove the assert() here? The module does nothing if assertions are disabled, but it doesn't tell you that.

longwave’s picture

If it turns out that an integration test is hard-to-impossible to write, I question the value of this module at all - is the JSON:API code robust enough that we can trust that it won't fail now? Perhaps this module should just become test-only?

bbrala’s picture

Thinking on this, the code was really for testing only since it is wrapped in assert to actually check. So i think you're right and it is testing only.

I've also manually checked if it runs on tests with:

 ../
vendor/bin/phpunit ../core/modules/jsonapi/tests/src/Functional/BlockTest.php

and have confirmed it works. Did change the services yml though.

bbrala’s picture

Status: Needs work » Needs review

Unrelated test failure.

longwave changed the visibility of the branch 3472008-move-jsonapi-validation to hidden.

longwave changed the visibility of the branch 3472008-hotfix-disable-validation to hidden.

longwave’s picture

Status: Needs review » Reviewed & tested by the community

Looks good to me, I can't think of a real world case for this unless you are extending JSON:API in some way, in which case you can still use this module in your tests.

I updated the change record a bit to match the new solution and hid the older MRs.

longwave’s picture

Priority: Critical » Major

Also downgrading to major since #3365985: Promote justinrainbow/json-schema from dev-dependency to full dependency was reverted in 11.3.x, but we should still land this for 11.4/12.0.

needs-review-queue-bot’s picture

Status: Reviewed & tested by the community » Needs work
StatusFileSize
new91 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

bbrala’s picture

Status: Needs work » Reviewed & tested by the community

Did a quick rebase, there were no conflics so setting back to rtbc.

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.

  • catch committed 700e0a91 on 11.x
    task: #3472008 Avoid JSON:API schema validation by default when assert...

  • catch committed 0895e778 on main
    task: #3472008 Avoid JSON:API schema validation by default when assert...

catch’s picture

Version: main » 11.x-dev
Status: Reviewed & tested by the community » Fixed

Committed/pushed to main and 11.x, thanks!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

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