gpt4 book ai didi

graphql - graphql 模式循环引用是反模式吗?

转载 作者:行者123 更新时间:2023-12-03 16:03:25 37 4
gpt4 key购买 nike

像这样的graphql模式:

type User {
id: ID!
location: Location
}

type Location {
id: ID!
user: User
}

现在,客户端发送一个 graphql询问。理论上, UserLocation可以无限循环互相引用。

我认为这是一种反模式。据我所知, graphql 中都没有中间件或方法来限制查询的嵌套深度。和 apollo社区。

这个无限嵌套深度查询会消耗我系统的大量资源,比如带宽、硬件、性能。不仅是服务器端,还有客户端。

因此,如果 graphql 模式允许循环引用,则应该有一些中间件或方法来限制查询的嵌套深度。或者,为查询添加一些约束。

也许不允许循环引用是一个更好的主意?

我更喜欢发送另一个查询并在一个查询中执行多个操作。这要简单得多。

更新

我找到了这个库: https://github.com/slicknode/graphql-query-complexity .如果 graphql 不限制循环引用。该库可以保护您的应用程序免受资源耗尽和 DoS 攻击。

最佳答案

这取决于。

It's useful to remember that the same solution can be a good pattern in some contexts and an antipattern in others. The value of a solution depends on the context that you use it. — Martin Fowler



循环引用可能会带来额外的挑战,这是一个有效的观点。正如您所指出的,它们是潜在的安全风险,因为它们使恶意用户能够制作可能非常昂贵的查询。根据我的经验,它们还使客户团队更容易无意中过度获取数据。

另一方面,循环引用允许更高级别的灵 active 。如果我们假设以下模式,则使用您的示例运行:
type Query {
user(id: ID): User
location(id: ID): Location
}

type User {
id: ID!
location: Location
}

type Location {
id: ID!
user: User
}

很明显,我们可能会进行两个不同的查询来有效地获取相同的数据:
{
# query 1
user(id: ID) {
id
location {
id
}
}

# query 2
location(id: ID) {
id
user {
id
}
}
}

如果您的 API 的主要消费者是一个或多个致力于同一个项目的客户团队,那么这可能并不重要。您的前端需要它获取的数据具有特定的形状,并且您可以围绕这些需求设计您的架构。如果客户端总是获取用户,可以通过这种方式获取位置并且不需要该上下文之外的位置信息,那么只有 user 可能是有意义的。查询并省略 user来自 Location 的字段类型。即使您需要 location查询,公开 user 可能仍然没有意义字段上,取决于您的客户的需求。

另一方面,假设您的 API 被大量客户端使用。也许你支持多个平台,或者多个应用程序做不同的事情但共享相同的 API 来访问你的数据层。或者,您可能正在公开一个旨在让第三方应用程序与您的服务或产品集成的公共(public) API。在这些情况下,您对客户需求的概念会更加模糊。突然间,公开各种查询基础数据的方法以满足当前客户和 future 客户的需求变得更加重要。对于单个客户端的 API 也可以这样说,其需求可能会随着时间的推移而发展。

始终可以按照您的建议“扁平化”您的架构并提供额外的查询,而不是实现关系字段。但是,这样做对客户来说是否“更简单”取决于客户。最好的方法可能是让每个客户选择适合他们需要的数据结构。

与大多数架构决策一样,需要权衡取舍,适合您的正确解决方案可能与其他团队不同。

如果你 有循环引用, 所有的希望都不会丢失 .一些实现具有用于限制查询深度的内置控件。 GraphQL.js 没有,但是那里有像 graphql-depth-limit 这样的库就是这样做的。值得指出的是,广度和深度一样是一个大问题——无论您是否有循环引用,您都应该在解析列表时考虑使用最大限制来实现分页,以防止客户潜在地请求一次记录数千条记录。

正如@DavidMaze 指出的那样,除了限制客户端查询的深度之外,您还可以使用 dataloader以减轻从数据层重复获取相同记录的成本。而 dataloader通常用于批处理请求以解决因延迟加载关联而引起的“n+1 问题”,它在这里也可以提供帮助。除了批处理,dataloader 还缓存加载的记录。这意味着同一记录的后续加载(在同一请求内)不会命中数据库,而是从内存中获取。

关于graphql - graphql 模式循环引用是反模式吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53863934/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com