Skip to content

Commit 707f257

Browse files
committed
add docs
1 parent 4ec12df commit 707f257

File tree

2 files changed

+102
-4
lines changed

2 files changed

+102
-4
lines changed

docs/executing-queries.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,3 +210,101 @@ $server = new StandardServer([
210210
'validationRules' => $myValidationRules
211211
]);
212212
```
213+
## Validation Caching
214+
215+
Validation is a required step in GraphQL execution, but it can become a performance bottleneck when the same queries are
216+
run repeatedly — especially in production environments where queries are often static or pre-generated (e.g., persisted
217+
queries or queries emitted by client libraries).
218+
219+
To optimize for this, graphql-php supports pluggable validation caching. By implementing the GraphQL\Validator\ValidationCache
220+
interface and passing it to GraphQL::executeQuery(), you can skip validation for queries already known to be valid:
221+
222+
To optimize for this, `graphql-php` supports pluggable validation caching. By implementing the `GraphQL\Validator\ValidationCache` interface and passing it to
223+
`GraphQL::executeQuery()`, you can skip validation for queries that are already known to be valid.
224+
225+
```php
226+
use GraphQL\Validator\ValidationCache;
227+
use GraphQL\GraphQL;
228+
use GraphQL\Tests\PsrValidationCacheAdapter;
229+
230+
$validationCache = new PsrValidationCacheAdapter();
231+
232+
$result = GraphQL::executeQuery(
233+
$schema,
234+
$queryString,
235+
$rootValue,
236+
$context,
237+
$variableValues,
238+
$operationName,
239+
$fieldResolver,
240+
$validationRules,
241+
$validationCache
242+
);
243+
```
244+
245+
### Key Generation Tips
246+
You are responsible for generating your own cache keys in a way that uniquely identifies the schema, the query, and
247+
(optionally) any custom validation rules. Here are some tips:
248+
249+
* Hash your schema once at build time and store the result in an environment variable or constant.
250+
* Avoid using serialize() on schema objects — closures and internal references may cause errors.
251+
* If using custom validation rules, be sure to account for them in your key (e.g., by serializing or listing their class names).
252+
* Consider including the graphql-php version number to account for internal rule changes across versions.
253+
254+
### Sample Implementation
255+
```php
256+
use GraphQL\Validator\ValidationCache;
257+
use GraphQL\Language\AST\DocumentNode;
258+
use GraphQL\Type\Schema;
259+
use GraphQL\Utils\SchemaPrinter;
260+
use Psr\SimpleCache\CacheInterface;
261+
use Composer\InstalledVersions;
262+
263+
/**
264+
* Reference implementation of ValidationCache using PSR-16 cache.
265+
*
266+
* @see GraphQl\Tests\PsrValidationCacheAdapter
267+
*/
268+
class PsrValidationCacheAdapter implements ValidationCache
269+
{
270+
private CacheInterface $cache;
271+
272+
private int $ttlSeconds;
273+
274+
public function __construct(
275+
CacheInterface $cache,
276+
int $ttlSeconds = 300
277+
) {
278+
$this->cache = $cache;
279+
$this->ttlSeconds = $ttlSeconds;
280+
}
281+
282+
public function isValidated(Schema $schema, DocumentNode $ast, ?array $rules = null): bool
283+
{
284+
$key = $this->buildKey($schema, $ast);
285+
return $this->cache->has($key);
286+
}
287+
288+
public function markValidated(Schema $schema, DocumentNode $ast, ?array $rules = null): void
289+
{
290+
$key = $this->buildKey($schema, $ast);
291+
$this->cache->set($key, true, $this->ttlSeconds);
292+
}
293+
294+
private function buildKey(Schema $schema, DocumentNode $ast, ?array $rules = null): string
295+
{
296+
// Use a stable hash for schema. In production, prefer a build-time constant:
297+
// $schemaHash = $_ENV['SCHEMA_VERSION'] ?? 'v1';
298+
$schemaHash = md5(SchemaPrinter::doPrint($schema));
299+
300+
// Serialize AST and rules — both are predictable and safe in this context
301+
$astHash = md5(serialize($ast));
302+
$rulesHash = md5(serialize($rules));
303+
304+
// Include graphql-php version to account for internal changes
305+
$libraryVersion = \Composer\InstalledVersions::getVersion('webonyx/graphql-php') ?: 'unknown';
306+
307+
return "graphql_validation_{$libraryVersion}_{$schemaHash}_{$astHash}_{$rulesHash}";
308+
}
309+
}
310+
```

src/Validator/ValidationCache.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@
1010
/**
1111
* Implement this interface and pass an instance to GraphQL::executeQuery to enable caching of successful query validations.
1212
*
13-
* This can improve performance by skipping validation for known-good query, schema, and rules combinations.
13+
* This can improve performance by skipping validation for known-good combinations of query, schema, and rules.
1414
* You are responsible for defining how cache keys are computed.
1515
*
1616
* Some things to keep in mind when generating keys:
1717
* - PHP's `serialize` method is fast, but can't handle certain structures such as closures.
18-
* - If your `schema` does include closures or is quite large and complex, consider
19-
* using some kind of build-time version number or other environment variable.
18+
* - If your `schema` includes closures or is too large or complex to serialize,
19+
* consider using a build-time version number or environment-based fingerprint instead.
2020
* - Keep in mind that there are internal `rules` that are applied in addition to any you pass in,
2121
* and it's possible these may shift or expand as the library evolves, so it might make sense
2222
* to include the library version number in your keys.
2323
*
24-
* @see PsrValidationCacheAdapter for a toy implementation.
24+
* @see PsrValidationCacheAdapter for a simple reference implementation.
2525
*/
2626
interface ValidationCache
2727
{

0 commit comments

Comments
 (0)