GraphQL 为列表和详细查询共享相同的对象类型

Posted

技术标签:

【中文标题】GraphQL 为列表和详细查询共享相同的对象类型【英文标题】:GraphQL share same Object type for list and detail query 【发布时间】:2020-01-17 00:34:20 【问题描述】:

我正在采用 GraphQL 作为多个后端微服务的数据组合层。我们有一个UserService,它提供了一些与用户相关的REST API,一个是/users,另一个是/detail?userId=$userId。 我有以下架构定义:

type User 
    userId: ID!
    name: String!
    address: String
    // ... some other fields

Query 
    users: [User]!
    userDetail(userId: ID): User

问题是,出于某种性能原因,/users 中的 User 项的字段少于 /detail。例如,address 字段不存在于 list API 中,而仅存在于 detail API 中。

那么,我们是否必须为 list 查询定义另一个 UserListItem?由于后端 API 的限制,我们不能在 listdetail 查询之间共享相同的 User 类型定义。

【问题讨论】:

【参考方案1】:

首先,我认为我们应该考虑一下为什么列表API中不存在地址字段?

在 Apollo 看来,相同的用户 id 应该得到相同的结果。 所以在你的情况下,这是不合理的。

如果不为列表查询定义其他类型将导致缓存问题(客户端)

您可以参考这篇文章了解更多信息

(相同的id,输入不同的结果)

https://kamranicus.com/posts/2018-03-06-graphql-apollo-object-caching

如果你为列表查询定义另一种类型也会导致缓存问题(关于客户端在变异后更新缓存)

当然,客户端可以通过设置 fetchPolicy 或手动更新缓存来解决缓存问题,但这并不是最好的解决方案。

所以如果我是后端开发人员,我会尝试将地址字段放入列表 API。

如果你真的不能把地址字段放在列表API中,我认为定义另一种类型会更好。

但是客户端需要更加注意更新缓存的问题。


例如,如果我们为用户定义另一种类型。 (输入UserDetail

假设我们有一个显示用户列表的页面(输入User),并且我们有一个修改用户信息的突变。

通常,当我们进入编辑页面时,我们会执行userDetail来初始化表单数据。(输入UserDetail

如果突变后返回类型为User,则用户列表中具有相同ID的用户将自动更新缓存。

(https://www.apollographql.com/docs/react/advanced/caching/#automatic-cache-updates)

但是当我们回到编辑页面时,你会发现 userDetail 的数据在突变后保持不变,因为突变的返回类型是 User 而不是 UserDetail

在这种情况下,我会将 fetchPolicy 设置为network-only(userDetail 查询),反之亦然。


相同的ID和类型,但不同的结果

参考这篇文章

https://kamranicus.com/posts/2018-03-06-graphql-apollo-object-caching

【讨论】:

感谢您的回复。 REST API 由其他后端开发人员管理。为什么 list API 中不存在address 或其他一些字段,通常它与性能有关。也许所有的User 数据都被分成TWO 数据库tables:一个表只保存一些简短的数据,另一个表包含更多的用户详细信息。通过将用户数据拆分成两张表,我们可以更快地读写 mysql。而当我们需要向用户展示list时,我们只需要从ONE表中SELECT,不需要加入另一个明细表。 @Jess 我了解您的情况,我更新了我的回答,描述了客户端可能遇到的问题。我不知道什么是最好的解决方案,所以我只是分享我的经验。对不起我的英语不好,希望你能明白我想表达的意思。 再次感谢您的体验。我从你的回答中学到了很多。顺便说一句,我认为你的英语很好

以上是关于GraphQL 为列表和详细查询共享相同的对象类型的主要内容,如果未能解决你的问题,请参考以下文章

在 Graphql 中解析类型

如何在我的GraphQL中为对象中的对象列表定义类型

GraphQL:如何重用相同的类型进行查询和变异?

GraphQL漏洞案例:获取任何Facebook用户的朋友列表和部分支付卡详细信息

如果在突变查询中添加列表类型,graphql 不会在 android 中编译

如何使用相同的参数查询 Graphql 2 对象