Repository: FormidableLabs/urql
Pull request #1304 (2021-01-13 17:59:29)

(graphCache) - warn when using an interface or union type in the resolvers
Resolves: https://github.com/FormidableLabs/urql/issues/1293

## Summary

Warn the user when using an abstract type in the resolvers config.

## Set of changes

- add dev-check to schema-predicates
- add documentation for said error

changeset-bot[bot]: ###  🦋  Changeset detected

Latest commit: 2f8686c83f206addc28f3141ad5c0fd8efc546c8

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 1 package</summary>

  | Name                      | Type  |
| ------------------------- | ----- |
| @urql/exchange-graphcache | Minor |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/master/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/FormidableLabs/urql/new/warn-abstract-fields?filename=.changeset/shiny-dancers-film.md&value=---%0A%22%40urql%2Fexchange-graphcache%22%3A%20patch%0A---%0A%0A(graphCache)%20-%20warn%20when%20using%20an%20interface%20or%20union%20type%20in%20the%20resolvers%0A)



Patch:
diff --git a/.changeset/late-gifts-worry.md b/.changeset/late-gifts-worry.md
new file mode 100644
index 00000000..273db843
--- /dev/null
+++ b/.changeset/late-gifts-worry.md
@@ -0,0 +1,5 @@
+---
+'@urql/exchange-graphcache': minor
+---
+
+Warn when using an interface or union field in the graphCache resolvers config.
diff --git a/docs/graphcache/errors.md b/docs/graphcache/errors.md
index 6d156d0a..adde0d90 100644
--- a/docs/graphcache/errors.md
+++ b/docs/graphcache/errors.md
@@ -376,3 +376,15 @@ schema {
 
 Where `YourMutation` and `YourSubscription` are your custom Operation Root Types, instead of relying
 on the default names `"Mutation"` and `"Subscription"`.
+
+## (26) Invalid abstract resolver
+
+> Invalid resolver: `???` does not map to a concrete type in the schema,
+> but the resolvers option is referencing it. Implement the resolver for the types that `??` instead.
+
+When you're passing an introspected schema to the cache exchange, it is
+able to check whether your `opts.resolvers` is valid.
+This error occurs when you are using an `interface` or `union` rather than an
+implemented type for these.
+
+Check the type mentioned and change it to one of the specific types.
diff --git a/exchanges/graphcache/src/ast/schemaPredicates.ts b/exchanges/graphcache/src/ast/schemaPredicates.ts
index 777de331..8075ccc6 100644
--- a/exchanges/graphcache/src/ast/schemaPredicates.ts
+++ b/exchanges/graphcache/src/ast/schemaPredicates.ts
@@ -177,6 +177,18 @@ function warnAboutResolver(name: string): void {
   );
 }
 
+function warnAboutAbstractResolver(
+  name: string,
+  kind: 'UNION' | 'INTERFACE'
+): void {
+  warn(
+    `Invalid resolver: \`${name}\` does not match to a concrete type in the schema, but the \`resolvers\` option is referencing it. Implement the resolver for the types that ${
+      kind === 'UNION' ? 'make up the union' : 'implement the interface'
+    } instead.`,
+    26
+  );
+}
+
 export function expectValidResolversConfig(
   schema: SchemaIntrospector,
   resolvers: ResolverConfig
@@ -201,6 +213,14 @@ export function expectValidResolversConfig(
     } else {
       if (!schema.types[key]) {
         warnAboutResolver(key);
+      } else if (
+        schema.types[key].kind === 'INTERFACE' ||
+        schema.types[key].kind === 'UNION'
+      ) {
+        warnAboutAbstractResolver(
+          key,
+          schema.types[key].kind as 'INTERFACE' | 'UNION'
+        );
       } else {
         const validTypeProperties = (schema.types[key] as SchemaObject).fields;
         for (const resolverProperty in resolvers[key]) {
diff --git a/exchanges/graphcache/src/helpers/help.ts b/exchanges/graphcache/src/helpers/help.ts
index 7454272b..1775a445 100644
--- a/exchanges/graphcache/src/helpers/help.ts
+++ b/exchanges/graphcache/src/helpers/help.ts
@@ -30,7 +30,8 @@ export type ErrorCode =
   | 22
   | 23
   | 24
-  | 25;
+  | 25
+  | 26;
 
 type DebugNode = ExecutableDefinitionNode | InlineFragmentNode;
 


Test patch:
diff --git a/exchanges/graphcache/src/store/store.test.ts b/exchanges/graphcache/src/store/store.test.ts
index 9e682a3e..d057819c 100644
--- a/exchanges/graphcache/src/store/store.test.ts
+++ b/exchanges/graphcache/src/store/store.test.ts
@@ -320,6 +320,26 @@ describe('Store with ResolverConfig', () => {
     expect(warnMessage).toContain('https://bit.ly/2XbVrpR#23');
   });
 
+  it('should warn when we use an interface type', function () {
+    new Store({
+      schema: minifyIntrospectionQuery(
+        require('../test-utils/simple_schema.json')
+      ),
+      resolvers: {
+        ITodo: {
+          complete: () => true,
+        },
+      },
+    });
+
+    expect(console.warn).toBeCalledTimes(1);
+    const warnMessage = mocked(console.warn).mock.calls[0][0];
+    expect(warnMessage).toContain(
+      'Invalid resolver: `ITodo` does not match to a concrete type in the schema, but the `resolvers` option is referencing it. Implement the resolver for the types that implement the interface instead.'
+    );
+    expect(warnMessage).toContain('https://bit.ly/2XbVrpR#26');
+  });
+
   it("should warn if a type's property doesn't exist in the schema", function () {
     new Store({
       schema: minifyIntrospectionQuery(