0

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,
});

Jules Betfien
  • 25
  • 2
  • 6

1 Answers1

1

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
  }
}
Michel Floyd
  • 18,793
  • 4
  • 24
  • 39
  • Thanks @Michel Floyd. On your rootResolevr you say ...userResolver.Query or . Mutation. But there is no Query or Mutation. in your resolevrs. I think it is a mistake. Please can you tell me the cons of my method? – Jules Betfien Aug 22 '23 at 22:23
  • You're attempting to build an object with multiple `Query` and `Mutation` top-level keys and that won't work. `resolvers = { Query: { …all the queries }, Mutation: {…all the mutations }}` – Michel Floyd Aug 22 '23 at 23:52