Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merging GraphQL Resolvers for Apollo Server not working with Object.assign()

I am modularizing my schema for a GraphQL API and trying to merge the resolvers without using any 3rd party libraries.

Is there a simple way to do this without Lodash.merge() or equivalent?

The Apollo Documentation says to use a library such as Lodash to merge() modularized resolvers. (http://dev.apollodata.com/tools/graphql-tools/generate-schema.html#modularizing)

The problem seems to be that by their nature, the resolvers contain functions as properties, so they seem to be omitted when I access them via Object.assign() or even JSON.stringify().

If I console.log them, I see: {"Query":{},"Mutation":{}}

Here is what one of the resolvers looks like:

 const productResolvers = {
   Query: {
     myProducts: (root, { userId }, context) => {
       return [
         { id: 1, amount: 100, expiry: '12625383984343', created: '12625383984343' },
         { id: 2, amount: 200, expiry: '12561351347311', created: '12625383984343' },
         { id: 3, amount: 200, expiry: '11346347378333', created: '12625383984343' },
         { id: 4, amount: 350, expiry: '23456234523453', created: '12625383984343' },
       ];
     },
   },
   Mutation: {
     addProduct: (root, { userId }, context) => {
       return { id: 350, amount: 100, expiry: '12625383984343', created: '12625383984343' };
     },
   }
 };

Let's assume there is another one virtually identical called widgetResolvers.

Here is a fully functional block of code:

 export const schema = makeExecutableSchema({
   typeDefs: [queries, mutations, productSchema, widgetSchema],
   resolvers
 });

Here is what I'm trying to achieve:

 export const schema = makeExecutableSchema({
   typeDefs: [queries, mutations, productSchema, widgetSchema],
   resolvers: Object.assign({}, productResolvers, widgetResolvers)
 });

I haven't loaded in ability to use rest spread yet (https://babeljs.io/docs/plugins/transform-object-rest-spread/). I suspect it won't work for the same reason Object.assign() doesn't work.

Oh, and here is why I suspect this merge doesn't work: Why doesn't JSON.stringify display object properties that are functions?

like image 248
agm1984 Avatar asked Jan 29 '23 21:01

agm1984


1 Answers

If you're using Object.assign(), your Query and Mutation properties shouldn't end up empty, but you will run into an issue because, unlike lodash's merge(), it's not recursive. Object.assign() only compares the "direct" properties of the objects it's passed -- overriding properties of previous sources as it moves through the list.

Because Query and Mutation are properties of the objects being passed, each subsequent resolver override the previous object's Query and Mutation, with the resulting object only holding the Query and Mutation properties of the last object passed into Object.assign().

It's a lot less neat, but if you're bent on avoiding importing lodash, you could get the expected behavior this way:

const productResolver = {
  Query: { ... ✂ ... },
  Mutation: { ... ✂ ... }
}

const widgetResolver = {
  Query: { ... ✂ ... },
  Mutation: { ... ✂ ... }
}

const resolvers = {
  Query: Object.assign({}, widgetResolver.Query, productResolver.Query),
  Mutation: Object.assign({}, widgetResolver.Mutation, productResolver.Mutation)
}

Got type resolvers too? No problem:

const Widget = { ... ✂ ... }
const Product = { ... ✂ ... }

const resolvers = Object.assign(
  {
    Query: Object.assign({}, widgetResolver.Query, productResolver.Query),
    Mutation: Object.assign({}, widgetResolver.Mutation, productResolver.Mutation)
  },
  Widget,
  Product)
like image 80
Daniel Rearden Avatar answered Feb 05 '23 16:02

Daniel Rearden