首页 > 解决方案 > GraphQL API 中的清洁架构和实体延迟加载

问题描述

我正在尽我的能力和理解力尝试按照清洁架构原则改进现有项目的架构,但我正在努力解决的问题之一是在 GQL 解析器中适合延迟加载实体的位置。

如果我们考虑拥有一个 Product 实体的示例,该实体在一对多类型的关系中与它相关联的类别(在我的应用程序中,它的 MTM,但为了简单起见,让我们继续吧),那么对应的 Product 类型看起来和这个相似

type Category {
  name: String!
  ...
}

type Product {
  ...
  name: String
  description: String
  categories: [Category!]!
}

客户可以查询表中的任何 Product 字段,products如果他需要访问与该产品关联的类别,他可以使用该categories字段。

为了避免过度获取,正确的做法似乎是最初仅从表中获取数据,如果客户端要求,则products有条件地从表中加载数据。categories

因此,要解析类别,我们需要有条件地查询categories表。

据我所知,我可以使用存储库模式来获取Product域对象并将其返回给 GrapQL 查询解析器。

但是,我不明白的是,查询附加实体的逻辑应该在哪里?

例如,如果Product域对象有一个方法,那么我可以loadCategories从解析器调用它Categories

const resolvers = {
  Product: {
    async categories(product, args, ctx) {
      return product.loadCategories()
    }
  } 
}

但是,这将要求 Product 对象依赖于RepositoryDAO 或另一个 DAO,据我所知,我不应该这样做。

我是否Repository在graphql的对象中注入一个或一个DAO context,并使用解析器中的那个?

这个似乎我会以一种方式倒退,但以另一种方式 - 不是那么多。因为根查询解析器有点像控制器,因此可以使用存储库。但是这个嵌套字段解析器在某种程度上属于Product域对象,我觉得这有点令人困惑。

另外,如果我有一个授权策略,比如说,它允许来宾用户阅读name产品的内容,而不是(如果他们无法阅读,description我应该返回),那么该逻辑应该存在于哪里?null

标签: node.jsgraphqlclean-architecture

解决方案


存储库或 [可能是外部的] 数据源通过上下文传递...

'父',第一个解析器arg是一个[通常]普通对象,具有解析数据属性(fe product.id)[通常]当前解析器需要[过滤/SQL where] ...

'父'(在这种情况下为产品)解析器可以返回带有字段/道具的对象......但您可以返回超过响应所需的内容......其中一个可以是带有 [lazy] 的 [lazy] 初始化(Product实体)实例getCategories()] getter ...但拥有自己的存储库访问权限?不使用 ctx 传递的存储库/数据源?或在“补水”期间注射...

...这个吸气剂应该返回什么?只有身份证?ACL -null在某些情况下?(使用上下文中的用户?)......它应该是一个极简数组{id, name/title}还是完整的类别条目?再次......这是一个Category解析器[-s]角色

会不会太复杂?也许适合一些业务逻辑/字段/道具?

字段的 ACL?解析器角色,也是

任何 [type] 解析器都可以使用存储库……它是一个图表……不仅适用于根解析器……这将是紧密耦合/依赖关系。


推荐阅读