I am using Apollo Server 4 and Prisma 5 to build a simple ecomm project. At the moment I am trying to set up my resolvers to be able to bidirectionally query for Users + their comments...and also query Comments as the top level and return it's associated user. In the database Comment table has an associated user_id FK relationship to the User table. User table does NOT have a comments id, thus a one -> many and many -> one relationship.
When I try to query a user, comments is null unless I write a separate resolver for it and then use Prisma orm to include the relationship. I don't want to follow this as it seems like an antipattern when using gql. What I want to accomplish is to have a userByEmail() resolver in my top level Query{} from my SDL...and then have a Comment: {} 2nd level object in my resolvers to then have the corresponding User be the parent argument coming in the resolver...this is more gql dependant than db dependant.
Relevant Prisma Models:
model User {
id String @id @default(uuid())
username String @unique
email String @unique
password String
first_name String
last_name String?
created_at DateTime @default(now())
updated_at DateTime @updatedAt
deleted Boolean @default(false)
comments Comment[]
ratings Rating[]
orders Order[]
UserAddress UserAddress[]
}
model Comment {
id String @id @default(uuid())
user User @relation(fields: [user_id], references: [id])
user_id String // Change type to String
product Product @relation(fields: [product_id], references: [id])
product_id String
content String
created_at DateTime @default(now())
updated_at DateTime @updatedAt
deleted Boolean @default(false)
}
Relevant schema.graphql types:
type Query {
"Get a user by their email"
userByEmail(email: String): User!
}
"This type represents a user in the system"
type User {
"Unique identifier for the user"
id: ID!
"Username for login"
username: String!
"User's email address"
email: String!
"User's first name"
first_name: String!
"User's last name (optional)"
last_name: String!
"List of comments authored by the user (optional)"
comments: [Comment]
"List of ratings created by the user (optional)"
ratings: [Rating]
"List of orders placed by the user (optional)"
orders: [Order]
"List of user's addresses"
addresses: [Address]
}
type Comment {
"Unique identifier for the comment"
id: ID!
"Content of the comment"
content: String!
"User who authored the comment"
user: User
"Product this comment is associated with"
product: Product
}
resolvers.ts
import { getUserByEmail, getCommentsByUserId } from '../../dataAccessLayer/orm/user';
import { User } from '../../generated/types';
// Use intersection type to combine Resolvers and Query
export const resolvers = {
Query: {
userByEmail: async (_parent: unknown, { email }: { email: string }) => {
console.log('parent', email);
const user = await getUserByEmail(email); // Already includes comments
return user;
},
},
Comment: {
userComments: (parent: User) => {
console.log('parent', parent);
const userId = parent.id;
return getCommentsByUserId(userId);
},
},
};
ORM DB Queries
import prisma from '../prismaClient';
export async function getUserByEmail(email: string) {
return await prisma.user.findUnique({
where: {
email,
},
});
}
export async function getCommentsByUserId(id: string) {
return await prisma.comment.findMany({
where: {
user_id: id,
},
include: {
user: true, // Include user relation
},
});
}
When I run my project I get this error:
Error: Comment.userComments defined in resolvers, but not in schema
[0] at addResolversToSchema
How can I properly query for sub fields using the Apollo Recommended approach of using (parent, args, context, info) arguments where parent should be the related user initially queried for when trying to get comments? This way I don't stitch together db queries at the orm level.
Thanks!
Take a look at the examples in apollo server doc, on how to implement resolvers
In the schema you have already included
commentsproperty to theUsertypeyou also defined
userByEmailto fetch user in top-level typeQueryNext, you need to implement resolvers for this schema. For the type
Queryyou need to implement resolver for the methoduserByEmail. You've done this partThe next thing you need to do, is to define resolver for
commentsproperty ofUser, which give you exactly what you want: user comments.And this is an example of the query compatible with our schema