3

I am using prisma client in my graphql server.

Following best practices, I made the resolver layer just a thin layer that delegates the actual fetching of data to a data access layer. The data access layer also does things like authorization and request level caching using dataloader.

I can't find a good way to fetch relations of entities in this setup because prisma client uses chaining of function calls on the promise object for fetching relations, but since my resolver doesn't call prisma client directly, it doesn't have access to the prisma client promise and so cannot call the chained relationship functions.

See the following example:

Sample data model:

type Apartment {
  id:               ID!
  floor:            Int
  building:         Building        @pgRelation(column: "building_id")
}

type Building {
  id:               ID!
  buildingNumber:   Int
}

Sample resolver for apartment:

module.exports = {
  Query: {
    apartment: async (parent, { where }, { apartmentDAO }) => {
      return apartmentDAO.apartment(where);
    }
  },
  Apartment: {
    building: async (parent, args, { buildingDAO }) => {
      return buildingDAO.buildingByApartmentId(parent.id);
    }
  }
};

Sample implementation of buildingByApartmentId in the data access layer:

buildingByApartmentId: (apartmentId) => {
  // Some authorization logic goes here
  // Some other common data access logic goes here
  // ....
  return prismaClient.apartment({ id: apartmentId }).building();
}

This is not a good implementation for a few reasons:

  1. I already fetched the apartment at it exists in the cache but I cannot reuse that because I have to fetch apartment again just to get to the building.
  2. For every relation in apartment I will need to implement a special function like this to fetch that specific relation by apartemntId. This is wasteful and misses the point of prisma implementing most of the queries for me.

Is there a better way to implement this that I am missing?

I know prisma binding would solve this issue but:

  1. Prisma client seems like the more up to date way of using primsa.
  2. For authorization purposes, prisma client is much more powerful.
brafdlog
  • 2,642
  • 1
  • 18
  • 21
  • Hi @brafdlog, I'm a a bit confused about your resolver setup. Where do the `apartmentDAO` and `buildingDAO` objects coming from that you retrieve from the `context`? Usually fetching relations in resolvers shouldn't be an issue since the Prisma Client has a built-in dataloader and will batch the requests that are sent to Prisma. We have a reference for implementing relations with the Prisma client [here](https://www.prisma.io/tutorials/a-guide-to-common-resolver-patterns-ct08/#scenario:-implementing-relations-with-prisma-client). This approach is as efficient as using Prisma bindings. – nburk Jan 17 '19 at 09:31
  • 1
    Hi @nburk, the DAOs are passed in the context. The reason for this is that each DAO uses a dataloader to cache calls in the same request and so I create an instance per request. I was not aware that prisma client uses a data loader internally and this may make my internal loader redundant. But the question still stands - the seperation to DAOs is for common fetching logic like authorization, logging and more. Don't want to repeat that in each resolver. BTW Is there any reference material on how the data loader inside prisma client works? – brafdlog Jan 17 '19 at 12:11
  • 2
    Our docs are unfortunately lacking behind at the moment, so we don't have any documentation about how exactly the dataloader works in Prisma client. We'll add that very soon. In the meantime, [this](https://github.com/prisma/prisma/issues/3586) and [this](https://github.com/prisma/prisma/issues/3599) GitHub issue might help a little to get a bit more context. – nburk Jan 17 '19 at 13:15
  • Thanks. Any insight on how to improve this implementation? If I could get the ids of the related entities that in itself could solve the redundant query but I don't think that is currently possible. – brafdlog Jan 17 '19 at 19:05

0 Answers0