Another way of merging graphql resolvers

215 views Asked by At

In many tutorials that I have read, the most common way of using graphql resolvers is like below.

export const rootResolvers: IResolvers = {
  Query: {
    getUserById: async (root, { id }, context, info) => {
      return await getUserController(id);
    },
    getUsers: async (root, args, context, info) => {
      return await getUsersController();
    },
  },
  Mutation: {
    createUser: async (_, args, {userData}, info) => {
      return registerUserController(userData);
    },

    updateUser: async (_, args, {userData}, info) => {
      return updateUserController(userData);
    },
  },
}

But I want to write directly the busness logic in my resolvers without using controllers, and since each resolevr can have a lot of code, I decided to split my rootResolver like this.

const getUserResolver = {
   Query: {
    getUsers: async (root, args, context, info) => {
      return await getUsersController();
    },
    },
   }
}
...

const userCreateResolver = {
   Mutation: {
    createUser: async (_, args, {userData}, info) => {
            return registerUserController(userData);
    },
   }
}

const userUpdateResolver = {
   Mutation: {
    updateUser: async (_, args, {userData}, info) => {
            return registerUserController(userData);
    },
   }
}

Now I use the spread operator to combine all my resolvers in order to obtain one resolver object.

const rootResolver: IResolvers = {
  ...getUserResolver.Query,
  ...userCreateResolver.Mutation,
  ...userUpdateResolver.Mutation
}

I want to know if this way is the best practise. Note: I used lodash and graphql-tools/merge packages but got an error on the definition of graphql server ( I am using @mercuriusjs and the resolver must be an object not an array of object.

// Register mercurius to the server.
app.register(mercurius, {
  schema: buildFederationSchema(rootTypeDefs, {
    isGateway: false,
  }),
  resolvers: rootResolver,  <--------------------
  context: buildContext,
  graphiql: true,
  queryDepth: 7,
});

1

There are 1 answers

2
Michel Floyd On BEST ANSWER

You can do this but don't include the Query or Mutation levels in your individual resolvers, use them at the end:

const getUserResolver = {
  getUsers: getUsersController
}

const userCreateResolver = {
  createUser: (_, __, {userData}) =>  registerUserController(userData)
}

const userUpdateResolver = {
  updateUser: (_, __, {userData}) =>  registerUserController(userData)
}

You don't have to await resolvers in their code, resolvers can return promises.

Then:

const rootResolver: IResolvers = { 
  Query: {
    ...getUserResolver.Query,
  },
  Mutation: {
    ...userCreateResolver.Mutation,
    ...userUpdateResolver.Mutation
  }
}