Skip to content

Cache result of validation #1730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 41 commits into
base: master
Choose a base branch
from
Open

Conversation

shmax
Copy link
Contributor

@shmax shmax commented Jul 11, 2025

Heyo, I remember there was some discussion about possibly disabling document validation checks a while back. I finally got around to looking into it and realized to my horror that it was indeed gobbling up a lot of resources in my app.

I don't know if you folks ever really agreed on a plan, but I thought I'd float this simple caching solution that leaves it up to the user.

Let me know what you think. If you like the general direction I can do a little polish and write better tests.

@shmax shmax changed the title cache result of validation Cache result of validation Jul 11, 2025
@shmax shmax force-pushed the validation-cache branch from 2d38364 to a2c38f4 Compare July 11, 2025 03:55
@shmax shmax force-pushed the validation-cache branch from 9ffbbd7 to 6782bad Compare July 11, 2025 04:07
@shmax shmax force-pushed the validation-cache branch from e3bc588 to 6317931 Compare July 12, 2025 00:05
@shmax shmax force-pushed the validation-cache branch from 1a59209 to 73c9774 Compare July 12, 2025 00:40
@shmax shmax force-pushed the validation-cache branch from 5e59b9c to 6d7ace0 Compare July 12, 2025 00:41
@shmax shmax force-pushed the validation-cache branch from 59f0ea0 to 708c85b Compare July 12, 2025 00:45
@shmax shmax force-pushed the validation-cache branch from a12854e to f35cb3c Compare July 12, 2025 01:53
@shmax shmax force-pushed the validation-cache branch from e6fa9a4 to d71e123 Compare July 12, 2025 04:00
@shmax shmax force-pushed the validation-cache branch from d1f3597 to c2a82a4 Compare July 14, 2025 14:26
@shmax shmax marked this pull request as ready for review July 14, 2025 17:32
Copy link
Collaborator

@spawnia spawnia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we are good with the implementation in its current form. Can you add documentation to docs/executing-queries.md? I think a section after Custom Validation Rules would work fine.

@shmax shmax force-pushed the validation-cache branch from 8fc2b53 to b5fdd3e Compare July 23, 2025 03:16
Copy link
Collaborator

@spawnia spawnia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some tricky details to figure out when implementing this. I really value putting in the time now to properly document them now to validate the design. I am going to try implenting the validation cache in https://github.com/nuwave/lighthouse and use that to battle-test it in one of my projects to see if anything else comes up.

Comment on lines 225 to 228
use GraphQL\GraphQL;
use GraphQL\Tests\PsrValidationCacheAdapter;

$validationCache = new PsrValidationCacheAdapter();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean to expose this class to end users? The directory /tests and subsequently the namespace GraphQL\Tests is excluded from the composer package through .gitattributes. My impression was that it serves only as a vehicle for our own unit tests and perhaps as an example implementation that we can point to.

I would probably recommend users to implement the interface concretely, perhaps we can just add something like this?

Suggested change
use GraphQL\GraphQL;
use GraphQL\Tests\PsrValidationCacheAdapter;
$validationCache = new PsrValidationCacheAdapter();
use GraphQL\GraphQL;
final class MyValidationCache implements ValidationCache { ... }
$validationCache = new MyValidationCache();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yeah, this is just meant to be a sample. I'll touch that up.

$errors = $context->getErrors();

if (isset($cache) && $errors === []) {
$cache->markValidated($schema, $ast, $rules);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch on not overwriting $rules 👍

* and it's possible these may shift or expand as the library evolves, so it might make sense
* to include the library version number in your keys.
*
* @see PsrValidationCacheAdapter for a simple reference implementation.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to /tests not being exported, this reference will lead nowhere for users that installed this package.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figure devs will be savvy enough to either clone the repo or look on github, but I can remove it for now if you like.

@spawnia
Copy link
Collaborator

spawnia commented Jul 23, 2025

I just found that Lighthouse already implements validation caching, see nuwave/lighthouse#2603. In general, the approach to hashing to schema and hashing the query string is the same, but there are some differences:

  1. Lighthouse offers special consideration for the QueryComplexity rule, which requires variables to work. Generally, validation rules do not have access to variable values, but this one has special treatment even in webonyx/graphql-php. The solution in Lighthouse splits validation in two phases, one where the cacheable rules (everything except QueryComplexity) are run/cached, then QueryComplexity maybe runs afterwards.
  2. Lighthouse has no considerations for the used library version of webonyx/graphql-php or nuwave/lighthouse itself, but probably should consider that.
  3. Lighthouse does not allow dynamically passing $rules ad-hoc, but users may overwrite the interface ProvidesCacheableValidationRules and change which validation rules are used. However, I found that using just the keys or class names of the used validation rules array is not sufficient. The validation rules for security such as QueryDepth are configurable and behave differently based on the configuration.

To resolve 1., perhaps we should add multi-phase validation to this library or some kind of special treatment for QueryComplexity.
Points 2. and 3. seem like something where Lighthouse is currently lacking but could be improved.

I am going to try adding a pull request to Lighthouse soon that implements its validation cache feature using the facilities offered through this pull request and perhaps extend it where its lacking.

@shmax
Copy link
Contributor Author

shmax commented Jul 24, 2025

Not sure I follow. I don't use Lighthouse, and I'm not familiar with it. What does it have to do with what I'm doing in this PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants