This sets up User, and Post objects with a few fields, and a me query that returns the current
user. There are a few things to note in this setup:
We split up the builder.objectRef and the implement calls, rather than calling
builder.objectRef(...).implement(...). This prevents typescript from getting tripped up by the
circular references between posts and users.
We use findUniqueOrThrow because those fields are not nullable. Using findUnique, prisma will
return a null if the object is not found. An alternative is to mark these fields as nullable.
The refs to our object types are called UserObject and PostObject, this is because User and
Post are the names of the types imported from prisma. We could instead alias the types when we
import them so we can name the refs to our GraphQL types after the models.
This setup is fairly simple, but it is easy to see the n+1 issues we might run into. Prisma helps
with this by batching queries together, but there are also things we can do in our implementation to
improve things.
One thing we could do if we know we will usually be loading the author any time we load a post is to
make the author part of shape required for a post:
const UserObject = builder.objectRef<User>('User');// We add the author here in the objectRefconst PostObject = builder.objectRef<Post & { author: User }>('Post');UserObject.implement({ fields: (t) => ({ id: t.exposeID('id'), email: t.exposeString('email'), posts: t.field({ type: [PostObject], resolve: (user) => db.post.findMany({ // We now need to include the author when we query for posts include: { author: true, }, where: { authorId: user.id }, }), }), }),});PostObject.implement({ fields: (t) => ({ id: t.exposeID('id'), title: t.exposeString('title'), author: t.field({ type: UserObject, // Now we can just return the author from the post instead of querying for it resolve: (post) => post.author, }), }),});
We may not always want to query for the author though, so we could make the author optional and fall
back to using a query if it was not provided by the parent resolver:
With this setup, a parent resolver has the option to include the author, but we have a fallback
incase it does not.
There are other patterns like data loaders than can be used to reduce n+1 issues, and make your
graph more efficient, but they are too complex to describe here.