Resolver Chaining

Hi,
my application has quite some authorization logic within the service layer, since RBAC is not suitable.
Now redwood generates services with predefined resolvers. These resolvers do not consider the logic of other services and therefore resolver chaining becomes pretty hard imo. Anyone has some recommendation on how to deal with this?
I will give you an example:

i.e. comments service

export const comments: QueryResolvers['comments'] = async() => {
   const currentUser = context.currentUser;
   await validateUser(currentUser)
   return db.comment.findMany({
       where: {
         userId: currentUser.id
        }
   })
}

i.e. post service

export const posts: QueryResolvers['posts'] = async() => {
   const currentUser = context.currentUser;
   await validateUser(currentUser)
   return db.post.findMany({
       where: {
         userId: currentUser.id
        },
       include: {
         comments: true
       }
   })
}

Now the generated resolver will return all comments related to a post and not only the ones of the user (this is just an example not a proper use case).

export const Post: PostRelationResolvers = {
  properties: (_obj, { root }) => {
    return db.post.findUnique({ where: { id: root?.id } }).comments()
  }

But I would like to keep the logic of the comments service. So I would write:

export const Post: PostRelationResolvers = {
  properties: (_obj, { root, context}) => {
    const currentUser = context.currentUser
    return comments(currentUser) 
// return db.post.findUnique({ where: { id: root?.id } }).comments()
  }

Now I am getting All! Comments, not only those related to posts.

So both the created service as well as the generated resolver do not server well as proper resolvers.

How would I create a proper resolver, without recreating the same logic as in the comments service?
I am in the posts resolver, knowing the posts id. I could probably adapt the comments service to accept the posts id to filter it like:
return comments(currentUser, root.id)
And adding it to the comments query. But is this really the proper way to do it?

export const comments: QueryResolvers['comments'] = async({args}) => {
   const currentUser = context.currentUser;
   await validateUser(currentUser)
   return db.comments.findMany({
       where: {
         userId: currentUser.id,
         postId: args.postId
        }
   })
}
1 Like

would you be willing to share the segments of your prisma file covering: user, post, comment?

it seems like this could be handled with some relations [ref: Relation queries (Concepts)]

thanks for your reply!

I think it should look like this:
You have an idea how to apply the relations differently?

model User {
  id                  String    @id @default(cuid())
  name                String    @unique
  hashedPassword      String
  salt                String
  resetToken          String?
  resetTokenExpiresAt DateTime?
  posts               Post[]
  comments            Comment[]
}

model Post {
   id        String    @id @default(cuid())
   user      User    @relation(fields: [userId], references: [id], onDelete: Cascade),
   userId    String
   comments  Comment[]
}

model Comment {
  id        String    @id @default(cuid())
  user      User    @relation(fields: [userId], references: [id], onDelete: Cascade),
  userId    String
  post      Post    @relation(fields: [postId], references: [id], onDelete: Cascade)
  postId    String
}

I think this would do it,

export const posts: QueryResolvers['posts'] = async() => {
   const currentUser = context.currentUser;
   await validateUser(currentUser)
   return db.post.findMany({
       where: {
         userId: currentUser.id
        },
       include: {
         comments: {
           where: {
             userId: currentUser.id
           }
         }
       }
   })
}

ref: [Filtering and sorting (Concepts)]

1 Like

Thanks I will try! :smiling_face:
Thanks for the links to doc, too!