How to Use lodash merge to Modularize GraphQL Resolvers
In this lesson, we'll see how we can use the lodash merge function to have our GraphQL resolvers map be broken down to small resolvers objects that pertain to certain domains (i.e modules).
Modularizing Resolvers#
π This lesson's quiz can be found - here.
ποΈ Solutions for this lesson's quiz can be found - here.
If our app was to continue to grow, our resolvers.ts
file will continue to get bigger to accommodate all the different resolvers within the different object types in our API. Though there's nothing inherently wrong with this, we can look to separate our resolvers into different resolvers maps (i.e. modules) in such a way that each resolvers map will pertain a particular domain (or module).
For example, assume we had a resolvers map just for resolvers that pertain to the listings domain (i.e. the listingResolvers
). The listings resolvers map will encompass all the resolvers that pertain to the listing domain or module such as the listings
query, the deleteListing
mutation, the id
resolver field for the Listing
object, etc.
export const listingResolvers: IResolvers = {
Query: {
listings: () => {
// ...
}
},
Mutation: {
deleteListing: () => {
// ...
}
},
Listing: {
id: () => {
// ...
}
}
};
We could have another resolvers map that deals with a different domain or module. For example, we can have a userResolvers
map that contained all the resolvers that pertain to retrieving or changing user data in our database.
export const userResolvers: IResolvers = {
Query: {
users: () => {
// ...
}
},
Mutation: {
deleteUser: () => {
// ...
}
},
User: {
id: () => {
// ...
}
}
};
This level of modularization will make no change to the actual functionality of our app but aim to have our resolvers be more concise and easier to read.
Let's set up the resolvers of our API to follow this level of modularization. The first thing we'll do is create a new folder called resolvers
in our src/graphql/
folder. The src/graphql/resolvers/
folder is where we'll place each of our different resolvers objects.
server/
src/
graphql/
resolvers/
// ...
// ...
In the src/graphql/resolvers/
folder, we'll create a sub-folder for each module we'd want to have a resolvers object. At this moment in time, we only have the capability to modify and read data about listings (i.e. we only have a listings collection), so we'll create a Listing/
sub-folder that contains an index.ts
file where we'll create and export a listingResolvers
map.
server/
src/
graphql/
resolvers/
Listing/
// ...
// ...
We'll move everything from our src/graphql/resolvers.ts
file to the index.ts
file in src/graphql/resolvers/Listing/
and rename the exported resolvers
object to listingResolvers
.
import { ObjectId } from "mongodb";
import { IResolvers } from "apollo-server-express";
import { Database, Listing } from "../../../lib/types";
export const listingResolvers: IResolvers = {
Query: {
listings: async (
_root: undefined,
_args: {},
{ db }: { db: Database }
): Promise<Listing[]> => {
return await db.listings.find({}).toArray();
}
},
Mutation: {
deleteListing: async (
_root: undefined,
{ id }: { id: string },
{ db }: { db: Database }
): Promise<Listing> => {
const deleteRes = await db.listings.findOneAndDelete({
_id: new ObjectId(id)
});
if (!deleteRes.value) {
throw new Error("failed to delete listing");
}
return deleteRes.value;
}
},
Listing: {
id: (listing: Listing): string => listing._id.toString()
}
};
We'll also remove the previously existing src/graphql/resolvers.ts
file.
lodash.merge
#
Since we only have a single resolvers map (listingResolvers
), we could reference the listingResolvers
map directly in our Apollo server instantiation. Instead, we'll look to prepare our app such that it is ready to accept and merge multiple different resolvers maps.
For us to pass multiple resolver objects into the ApolloServer
constructor, we must find a way to merge them into a single object. Luckily, there is an npm package perfect for this and it comes from lodash.
This page is a preview of TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL