Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
1---
2title: Local Directives
3order: 3
4---
5
6# Local Directives
7
8Previously, we've learned about local resolvers [on the "Normalized Caching"
9page](./normalized-caching.md#manually-resolving-entities) and [the "Local Resolvers" page](./local-resolvers.md).
10
11Resolvers allow us to change the data that Graphcache resolvers for a given field on a given type.
12This, in turn, allows us to change which links and data are returned in a query’s result, which
13otherwise may not be cached or be returned in a different shape.
14
15Resolvers are useful to globally change how a field behaves, for instance, to tell Graphcache that
16a `Query.item(id: $id)` field returns an item of type `Item` with the `id` field, or to transform
17a value before it’s used in the UI.
18
19However, resolvers are limited to changing the behaviour globally, not to change a field’s behaviour
20per query. This is why **local directives** exist.
21
22## Adding client-only directives
23
24Any directive in our GraphQL documents that’s prefixed with an underscore character (`_`) will be
25filtered by `@urql/core`. This means that our GraphQL API never sees it and it becomes
26a “client-only directive”.
27
28No matter whether we prefix a directive or not however, we can define local resolvers for directives
29in Graphcache’s configuration and make conditional local resolvers.
30
31```js
32cacheExchange({
33 directives: {
34 pagination(directiveArgs) {
35 // This resolver is called for @_pagination directives
36 return (parent, args, cache, info) => {
37 return null;
38 };
39 },
40 },
41});
42```
43
44Once we define a directive on the `directives` configuration object, we can reference it in our
45GraphQL queries.
46
47As per the above example, if we now reference `@_pagination` in a query, the resolver that’s
48returned in the configuration will be applied to the field, just like a local resolver.
49
50We can also reference the directive using `@pagination`, however, this will mean that it’s
51also sent to the API, so this usually isn’t what we want.
52
53## Client-controlled Nullability
54
55Graphcache comes with two directives built-in by default. The `optional` and `required` directives.
56These directives can be used as an alternative to [the Schema Awareness
57feature’s](./schema-awareness.md) ability to generate partial results.
58
59If we were to write a query that contains `@_optional` on a field, then the field is always allowed to be
60nullable. In case it’s not cached, Graphcache will be able to replace it with a `null`
61value.
62
63Similarly, if we annotate a field with `@_required`, the value is not optional and, even if the
64cache knows the value is set to `null`, it will become required and Graphcache will either cascade
65to the next higher parent field annotated with `@_optional`, or will mark a query as a cache-miss.
66
67## Pagination
68
69Previously, in [the “Local Resolvers” page’s Pagination section](./local-resolvers.md#pagination) we
70defined a local resolver to add infinite pagination to a given type’s field.
71
72If we add the `simplePagination` or `relayPagination` helpers as directives instead, we can still
73use our schema’s pagination field as normal, and instead, only use infinite pagination as required.
74
75```js
76import { simplePagination } from '@urql/exchange-graphcache/extras';
77import { relayPagination } from '@urql/exchange-graphcache/extras';
78
79cacheExchange({
80 directives: {
81 simplePagination: options => simplePagination({ ...options }),
82 relayPagination: options => relayPagination({ ...options }),
83 },
84});
85```
86
87Defining directives for our resolver factory functions means that we can now use them selectively.
88
89```graphql
90{
91 todos(first: 10) @_relayPagination(mergeMode: "outwards") {
92 id
93 text
94 }
95}
96```
97
98### Reading on
99
100[On the next page we'll learn about "Cache Updates".](./cache-updates.md)