Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs(graphcache): Add advanced resolver tips (#3337)

authored by

Phil Pluckthun and committed by
GitHub
9fad2dc6 3afa8022

+115
+115
docs/graphcache/local-resolvers.md
··· 454 454 The cache read methods are not possible outside of GraphQL operations. This means these methods will 455 455 be limited to the different `Graphcache` configuration methods. 456 456 457 + ## Living with limitations of Local Resolvers 458 + 459 + Local Resolvers are powerful tools using which we can tell Graphcache what to do with a certain 460 + field beyond using results it’s seen on prior API results. However, it’s limitations come from this 461 + very intention they were made for. 462 + 463 + Resolvers are meant to augment Graphcache and teach it what to do with some fields. Sometimes this 464 + is trivial and simple (like most examples on this page), but other times, fields are incredibly 465 + complex to reproduce and hence resolvers become more complex. 466 + 467 + This section is not exhaustive, but documents some of the more commonly asked for features of 468 + resolvers. However, beyond the cases listed below, resolvers are limited and: 469 + 470 + - can't manipulate or see other fields on the current entity, or fields above it. 471 + - can't update the cache (they're only “computations” but don't change the cache) 472 + - can't change the query document that's sent to the API 473 + 474 + ### Writing reusable resolvers 475 + 476 + As we've seen before in the ["Transforming Records" section above](#transforming-records), we can 477 + write generic resolvers by using the fourth argument that resolvers receive, the `ResolveInfo` 478 + object. 479 + 480 + This `info` object gives our resolvers some context on where they’re being executed and gives it 481 + information about the current field and its surroundings. 482 + 483 + For instance, while Graphcache has a convenience helper to access a current record on the parent 484 + object for scalar values, it doesn't for links. Hence, if we're trying to read relationships we have 485 + to use `cache.resolve`. 486 + 487 + ```js 488 + cacheExchange({ 489 + resolvers: { 490 + Todo: { 491 + // This works: 492 + updatedAt: parent => parent.updatedAt, 493 + // This won't work: 494 + author: parent => parent.author, 495 + }, 496 + }, 497 + }); 498 + ``` 499 + 500 + The `info` object actually gives us two ways of accessing the original field's value: 501 + 502 + ```js 503 + const resolver = (parent, args, cache, info) => { 504 + // This is the full version 505 + const original = cache.resolve(info.parentKey, info.fieldName, args); 506 + // But we can replace `info.parentKey` with `parent` as a shortcut 507 + const original = cache.resolve(parent, info.fieldName, args); 508 + // And we can also avoid re-using arguments by using `fieldKey` 509 + const original = cache.resolve(parent, info.fieldKey); 510 + }; 511 + ``` 512 + 513 + Apart from telling us how to access the originally cached field value, we can also get more 514 + information from `info` about our field. For instance, we can: 515 + 516 + - Read the current field's name using `info.fieldName` 517 + - Read the current field's key using `info.parentFieldKey` 518 + - Read the current parent entity's key using `info.parentKey` 519 + - Read the current parent entity's typename using `info.parentTypename` 520 + - Access the current operation's raw variables using `info.variables` 521 + - Access the current operation's raw fragments using `info.fragments` 522 + 523 + ### Causing cache misses and partial misses 524 + 525 + When we write resolvers we provide Graphcache with a value for the current field, or rather with 526 + "behavior", that it will execute no matter whether this field is also cached or not. 527 + 528 + This means that, unless our resolver returns `undefined`, if the query doesn't have any other cache 529 + misses, Graphcache will consider the field a cache hit and will, unless other cache misses occur, 530 + not make a network request. 531 + 532 + > **Note:** An exception for this is [Schema Awareness](./schema-awareness.md), which can 533 + > automatically cause partial cache misses. 534 + 535 + However, sometimes we may want a resolver to return a result, while still sending a GraphQL API 536 + request in the background to update our resolver’s values. 537 + 538 + To achieve this we can update the `info.partial` field. 539 + 540 + ```js 541 + cacheExchange({ 542 + resolvers: { 543 + Todo: { 544 + author(parent, args, cache, info) { 545 + const author = cache.resolve(parent, info.fieldKey); 546 + if (author === null) { 547 + info.partial = true; 548 + } 549 + return author; 550 + }, 551 + }, 552 + }, 553 + }); 554 + ``` 555 + 556 + Suppose we have a field that our GraphQL schema _sometimes_ returns a `null` value for, but that may 557 + be upated with a value in the future. In the above example, we wrote a resolver that sets 558 + `info.partial = true` if a field’s value is `null`. This causes Graphcache to consider the result 559 + “partial and stale” and will cause it to make a background request to the API, while still 560 + delivering the outdated result. 561 + 562 + ### Conditionally applying resolvers 563 + 564 + We may not always want a resolver to be used. While sometimes this can be dangerous (if your 565 + resolver affects the shape and types of your fields), in other cases this is necessary. 566 + For instance, if your resolver handles infinite-scroll pagination, like the examples [in the next 567 + section](#pagination), then you may not always want to apply this resolver. 568 + 569 + For this reason, Graphcache also supports [“local directives”, which are introduced on the next docs 570 + page.](./local-directives.md) 571 + 457 572 ## Pagination 458 573 459 574 `Graphcache` offers some preset `resolvers` to help us out with endless scrolling pagination, also