Skip to content

Commit 8cad088

Browse files
authored
Merge pull request #185 from graphql-java/query-directives-documentation
Add query/operation directives documentation
2 parents c64aeba + b36c8f0 commit 8cad088

File tree

2 files changed

+276
-0
lines changed

2 files changed

+276
-0
lines changed

versioned_docs/version-v22/sdl-directives.md renamed to documentation/directives.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ title: "SDL directives"
33
date: 2018-09-09T12:52:46+10:00
44
description: How SDL Directives can be used to adjust the behavior of your graphql API
55
---
6+
# Directives
7+
8+
[Directives](https://spec.graphql.org/draft/#sec-Language.Directives) are a powerful feature of GraphQL, allowing you to declare additional data to a schema or document. This data can then be used to change runtime execution or type validation behavior.
9+
10+
There are two broad categories of directives, schema and operation directives. Schema directives are used on schema elements, and operation directives are used in operations within a GraphQL document.
11+
12+
Often, operation directives are also called "query directives", although they can be used in any GraphQL operation. Whilst both names can be used interchangeably, note that GraphQL Java class names use "query directives".
13+
14+
Note for those who love the details: the terminology of directives is a bit confusing. It is technically possible to define a directive that is both a schema and operation directive, in other words, defined for both schema and operation locations. However in practice, this is not common.
15+
616
# Schema Directives
717

818
## Adding Behaviour
@@ -298,3 +308,131 @@ type Query {
298308

299309
When the above was executed each directive would be applied one on top of the other. Each directive implementation should be careful
300310
to preserve the previous data fetcher to retain behaviour (unless of course you mean to throw it away)
311+
312+
# Operation Directives (also known as Query Directives)
313+
Let's define an operation directive `@cache`, which can be used on operation fields.
314+
315+
```graphql
316+
# Can only be used on a field in a GraphQL document
317+
directive @cache on FIELD
318+
319+
type Query {
320+
pet: Pet
321+
}
322+
323+
type Pet {
324+
name: String
325+
lastTimeOutside: String
326+
}
327+
```
328+
329+
We can only use this `@cache` directive on fields in a GraphQL document, which contains operations.
330+
331+
```graphql
332+
query myPet {
333+
pet {
334+
name
335+
lastTimeOutside @cache
336+
}
337+
}
338+
```
339+
340+
Directives can also have arguments. Let's add a `maxAge` argument, with a default value of 1000.
341+
342+
```graphql
343+
# Argument with a default value
344+
directive @cache(maxAge: Int = 1000) on FIELD
345+
```
346+
347+
In a GraphQL document, we could use our updated `@cache` directive to specify a maxAge value:
348+
349+
```graphql
350+
query myPet {
351+
pet {
352+
name
353+
lastTimeOutside @cache(maxAge: 500)
354+
}
355+
}
356+
```
357+
358+
All custom schema and operation directives don't have any effect until we implement new custom behavior. For example, the operation above where `lastTimeOutside` has a `@cache` directive behaves exactly the same as without it, until we have implemented some new logic. We'll demonstrate implementation of behavior for directives in the next section of this page.
359+
360+
Here is an operation directive with all possible eight locations in a GraphQL document, which contains operations.
361+
362+
```graphql
363+
type @foo on QUERY | MUTATION | SUBSCRIPTION |
364+
FIELD | FRAGMENT_DEFINITION | FRAGMENT_SPREAD |
365+
INLINE_FRAGMENT | VARIABLE_DEFINITION
366+
367+
query someQuery(
368+
$var: String @foo # Variable definition
369+
) @foo # Query
370+
{
371+
field @foo # Field
372+
... on Query @foo { # Inline fragment
373+
field
374+
}
375+
...someFragment @foo # Fragment spread
376+
}
377+
378+
fragment someFragment @foo { # Fragment
379+
field
380+
}
381+
382+
mutation someMutation @foo { # Mutation
383+
field
384+
}
385+
386+
subscription someSubscription @foo { # Subscription
387+
field
388+
}
389+
```
390+
391+
Although it is technically possible to define a directive that includes locations associated with schema and operation directives, in practice this is not common.
392+
393+
## Implementing logic for operation directives
394+
395+
Let's implement the logic for a `@cache` operation directive:
396+
397+
```graphql
398+
directive @cache(maxAge: Int) on FIELD
399+
```
400+
401+
This is an operation directive that enables clients to specify how recent cache entries must be. This is an example of an operation directive that can change execution.
402+
403+
For example, a client specifies that `hello` cache entries must not be older than 500 ms, otherwise we re-fetch these entries.
404+
405+
```graphql
406+
query caching {
407+
hello @cache(maxAge: 500)
408+
}
409+
```
410+
411+
In GraphQL Java, operation directive definitions are represented as `GraphQLDirective`s. Operation directive usages are represented as `QueryAppliedDirective`s. Note that the word "query" here is misleading, as it actually refers to a directive that applies to any of the three GraphQL operations: queries, mutations, or subscriptions. Operation directives are still commonly referred to as "query" directives, hence the class name.
412+
413+
Usages of operation directives are represented in GraphQL Java as instances of `QueryAppliedDirective`, and provided argument values are represented as `QueryAppliedDirectiveArgument`.
414+
415+
We can access operation directives usage during execution via `getQueryDirectives()` in `DataFetchingEnvironment`. For example:
416+
417+
```java
418+
DataFetcher<?> cacheDataFetcher = new DataFetcher<Object>() {
419+
@Override
420+
public Object get(DataFetchingEnvironment env) {
421+
QueryDirectives queryDirectives = env.getQueryDirectives();
422+
List<QueryAppliedDirective> cacheDirectives = queryDirectives
423+
.getImmediateAppliedDirective("cache");
424+
// We get a List, because we could have
425+
// repeatable directives
426+
if (cacheDirectives.size() > 0) {
427+
QueryAppliedDirective cache = cacheDirectives.get(0);
428+
QueryAppliedDirectiveArgument maxAgeArgument
429+
= cache.getArgument("maxAge");
430+
int maxAge = maxAgeArgument.getValue();
431+
432+
// Now we know the max allowed cache time and
433+
// can make use of it
434+
// Your logic goes here
435+
}
436+
}
437+
};
438+
```

documentation/sdl-directives.md renamed to versioned_docs/version-v22/directives.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ title: "SDL directives"
33
date: 2018-09-09T12:52:46+10:00
44
description: How SDL Directives can be used to adjust the behavior of your graphql API
55
---
6+
# Directives
7+
8+
[Directives](https://spec.graphql.org/draft/#sec-Language.Directives) are a powerful feature of GraphQL, allowing you to declare additional data to a schema or document. This data can then be used to change runtime execution or type validation behavior.
9+
10+
There are two broad categories of directives, schema and operation directives. Schema directives are used on schema elements, and operation directives are used in operations within a GraphQL document.
11+
12+
Often, operation directives are also called "query directives", although they can be used in any GraphQL operation. Whilst both names can be used interchangeably, note that GraphQL Java class names use "query directives".
13+
14+
Note for those who love the details: the terminology of directives is a bit confusing. It is technically possible to define a directive that is both a schema and operation directive, in other words, defined for both schema and operation locations. However in practice, this is not common.
15+
616
# Schema Directives
717

818
## Adding Behaviour
@@ -298,3 +308,131 @@ type Query {
298308

299309
When the above was executed each directive would be applied one on top of the other. Each directive implementation should be careful
300310
to preserve the previous data fetcher to retain behaviour (unless of course you mean to throw it away)
311+
312+
# Operation Directives (also known as Query Directives)
313+
Let's define an operation directive `@cache`, which can be used on operation fields.
314+
315+
```graphql
316+
# Can only be used on a field in a GraphQL document
317+
directive @cache on FIELD
318+
319+
type Query {
320+
pet: Pet
321+
}
322+
323+
type Pet {
324+
name: String
325+
lastTimeOutside: String
326+
}
327+
```
328+
329+
We can only use this `@cache` directive on fields in a GraphQL document, which contains operations.
330+
331+
```graphql
332+
query myPet {
333+
pet {
334+
name
335+
lastTimeOutside @cache
336+
}
337+
}
338+
```
339+
340+
Directives can also have arguments. Let's add a `maxAge` argument, with a default value of 1000.
341+
342+
```graphql
343+
# Argument with a default value
344+
directive @cache(maxAge: Int = 1000) on FIELD
345+
```
346+
347+
In a GraphQL document, we could use our updated `@cache` directive to specify a maxAge value:
348+
349+
```graphql
350+
query myPet {
351+
pet {
352+
name
353+
lastTimeOutside @cache(maxAge: 500)
354+
}
355+
}
356+
```
357+
358+
All custom schema and operation directives don't have any effect until we implement new custom behavior. For example, the operation above where `lastTimeOutside` has a `@cache` directive behaves exactly the same as without it, until we have implemented some new logic. We'll demonstrate implementation of behavior for directives in the next section of this page.
359+
360+
Here is an operation directive with all possible eight locations in a GraphQL document, which contains operations.
361+
362+
```graphql
363+
type @foo on QUERY | MUTATION | SUBSCRIPTION |
364+
FIELD | FRAGMENT_DEFINITION | FRAGMENT_SPREAD |
365+
INLINE_FRAGMENT | VARIABLE_DEFINITION
366+
367+
query someQuery(
368+
$var: String @foo # Variable definition
369+
) @foo # Query
370+
{
371+
field @foo # Field
372+
... on Query @foo { # Inline fragment
373+
field
374+
}
375+
...someFragment @foo # Fragment spread
376+
}
377+
378+
fragment someFragment @foo { # Fragment
379+
field
380+
}
381+
382+
mutation someMutation @foo { # Mutation
383+
field
384+
}
385+
386+
subscription someSubscription @foo { # Subscription
387+
field
388+
}
389+
```
390+
391+
Although it is technically possible to define a directive that includes locations associated with schema and operation directives, in practice this is not common.
392+
393+
## Implementing logic for operation directives
394+
395+
Let's implement the logic for a `@cache` operation directive:
396+
397+
```graphql
398+
directive @cache(maxAge: Int) on FIELD
399+
```
400+
401+
This is an operation directive that enables clients to specify how recent cache entries must be. This is an example of an operation directive that can change execution.
402+
403+
For example, a client specifies that `hello` cache entries must not be older than 500 ms, otherwise we re-fetch these entries.
404+
405+
```graphql
406+
query caching {
407+
hello @cache(maxAge: 500)
408+
}
409+
```
410+
411+
In GraphQL Java, operation directive definitions are represented as `GraphQLDirective`s. Operation directive usages are represented as `QueryAppliedDirective`s. Note that the word "query" here is misleading, as it actually refers to a directive that applies to any of the three GraphQL operations: queries, mutations, or subscriptions. Operation directives are still commonly referred to as "query" directives, hence the class name.
412+
413+
Usages of operation directives are represented in GraphQL Java as instances of `QueryAppliedDirective`, and provided argument values are represented as `QueryAppliedDirectiveArgument`.
414+
415+
We can access operation directives usage during execution via `getQueryDirectives()` in `DataFetchingEnvironment`. For example:
416+
417+
```java
418+
DataFetcher<?> cacheDataFetcher = new DataFetcher<Object>() {
419+
@Override
420+
public Object get(DataFetchingEnvironment env) {
421+
QueryDirectives queryDirectives = env.getQueryDirectives();
422+
List<QueryAppliedDirective> cacheDirectives = queryDirectives
423+
.getImmediateAppliedDirective("cache");
424+
// We get a List, because we could have
425+
// repeatable directives
426+
if (cacheDirectives.size() > 0) {
427+
QueryAppliedDirective cache = cacheDirectives.get(0);
428+
QueryAppliedDirectiveArgument maxAgeArgument
429+
= cache.getArgument("maxAge");
430+
int maxAge = maxAgeArgument.getValue();
431+
432+
// Now we know the max allowed cache time and
433+
// can make use of it
434+
// Your logic goes here
435+
}
436+
}
437+
};
438+
```

0 commit comments

Comments
 (0)