Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing an Apollo resolver for an interface

Let's say I have the following typedef:

interface Node {
  id: ID!
}

type Foo implements Node {
  id: ID!
  quantity: Int
}

type Bar implements Node {
  id: ID!
  name: String
}

Every ID I send out, I want to process in the same way. Currently I need some resolver like:

{
  // ...
  Foo: {
    id: (root) => encodeId(root.id, root.type),
    // ...
  },
  Bar: {
    id: (root) => encodeId(root.id, root.type),
    // ...
  },
  // ...
}

With many types implementing Node, this results in a lot of code duplication and it would be quite easy for a dev to forget the correct way to encode the ids, or forget to encode them all together.

Is there some way to do something like this?

{
  // ...
  Node: {
    __resolveType: (root) => root.type,
    id: (root) => encodeId(root.id, root.type)
  },
  // ...
}

Such that Foo, Bar and any other implementation of Node would inherit the id resolver?

like image 585
SCB Avatar asked Oct 18 '25 10:10

SCB


2 Answers

For anyone still stumbling on this question, you can set the inheritResolversFromInterfaces flag in makeExecutableSchema to true.

Found it here: https://github.com/apollographql/graphql-tools/issues/762#issuecomment-385591309

Apollo documentation here: https://www.apollographql.com/docs/apollo-server/api/apollo-server/#makeexecutableschema

like image 197
rooch84 Avatar answered Oct 21 '25 01:10

rooch84


This is an interesting question. I am not sure a resolver for an interface will accept anything other than __resolveType.

I occasionally run into something like this but I fix it with default and composed resolvers.

For example, for Node, you could have the following default resolvers:

const defaultNodeIdResolver = (root) => encodeId(root.id, root.type)
const defaultNodeOtherFieldResolver = (root) => root /* do something */

const defaultNodeResolvers = {
  id: defaultNodeIdResolver,
  otherField: defaultNodeOtherFieldResolver,
}

Then you could implement the other as follows:

{
  // ...
  Foo: {
    // use object spread
    ...defaultNodeResolvers,
    // ...
  },
  Bar: {
    // pick a specific resolver
    id: defaultNodeIdResolver,
    // ...
  },
  Baz: {
    ...defaultNodeResolvers,
    // you can even "override"
    id: (root) => root,
  },
}

This also helps to decouple your resolver logic from the resolver definitions. I would recommend that as a project grows. You could also work in resolver composition (see https://www.apollographql.com/docs/graphql-tools/resolvers.html#graphql-resolvers).

You just need to make sure you have access to the object spread. You should anyway. It's very helpful.

like image 29
Casey Benko Avatar answered Oct 21 '25 01:10

Casey Benko



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!