GraphQL:在同一查询中使用输入类型及其字段之一

Posted

技术标签:

【中文标题】GraphQL:在同一查询中使用输入类型及其字段之一【英文标题】:GraphQL: Use input type and one of its fields in the same query 【发布时间】:2020-06-07 11:53:19 【问题描述】:

我想知道如何在同一个 GraphQL 查询中同时使用输入类型及其字段之一作为参数。我认为有一些有效的解决方案,但我想知道哪些(如果有的话)是最佳实践。

考虑以下假设查询。我们通过位置和状态获取玩家,以及在同一位置的团队成员,但 member 字段只有一个 location 参数:

input PlayerInput 
  location: String!
  status: Int!


query getPlayers($playerInput: PlayerInput) 
  players(playerInput: $playerInput) 
    name
    team 
      name
      members(location: ???)  // <-- How to access playerInput.location?
        name
      
    
  

我能想出几个办法来解决这个问题:

1.更改查询以获取单个参数

query getPlayers($location: String!, $status: Int!) 
  players(playerInput:  location: $location, status: $status ) 
    name
    team 
      name
      members(location: $location) 
        name
      
    
  

2。更新架构,以便 members 采用正确的输入类型

query getPlayers($playerInput: PlayerInput) 
  players(playerInput: $playerInput) 
    name
    team 
      name
      members(playerInput: $playerInput)  // <-- Requires changing schema
        name
      
    
  

由于某些原因,这似乎不太好,并且只有在您能够更新架构时才有效。

3.将location 作为冗余的单个参数传入

query getPlayers($playerInput: PlayerInput, $location: String!) 
  players(playerInput: $playerInput) 
    name
    team 
      name
      members(location: $location) 
        name
      
    
  

这看起来不错,只是在创建查询时有一些重复:

const location = 'US';
const status = 1;

fetch(
  query: getPlayersQuery,
  variables: 
    location,
    playerInput: 
      location,
      status,
    
  
)...

这些是做这种事情的首选方式吗?还有其他我没有考虑过的方法吗?

【问题讨论】:

我肯定更喜欢 #1 或 #3 而不是 #2 - 仅更改架构以支持一个特殊查询是不行的。除非您真的打算让团队的members 可以由isActive 过滤,并且您的查询确实只想获取活跃玩家的活跃队友和不活跃玩家的不活跃队友。 这是有道理的 - #2 对我来说似乎也是不行的,只是想确认一下。 #1对我来说似乎最干净,只是在寻找第二个意见。谢谢! 【参考方案1】:

在采用输入类型的单个参数(选项 #1)上使用多个参数有时是有意义的在概念上,但它缺乏任何其他真正的优点,并且具有使变量定义不必要地冗长的缺点.在我看来,使用输入类型通常也会更好地执行类型。仅仅为了避免重复而更改架构是不值得的。

仅当两个字段都需要所有这些输入字段时,才应在两个字段上使用相同的输入对象类型(选项 #2)。这样做只是为了避免重复是一个坏主意 - 它有效地引入了未使用的输入,这对于任何使用 API 的其他开发人员来说都不是一个好的体验。

选项#3 很好。它还把球放在前端开发者的球场上——如果他们想要避免重复,他们也可以很容易地做到这一点,而无需你引入额外的论据:

query getPlayers($status: Int!, $location: String!) 
  players(playerInput:  status: $status, location: $location ) 
    name
    team 
      name
      members(location: $location) 
        name
      
    
  

但是,重复很可能实际上是一件好事。您不会经常遇到这些场景,因为我们正在处理图表数据. playersteammembers 字段都是层次结构的一部分,其中父字段约束子字段返回的数据——例如,members 不会返回所有成员,只是返回其中的成员特定的团队。这意味着,在大多数情况下,如果您将 players 限制为仅包含来自特定位置的数据,那么您也将限制由 members 等子字段返回的数据。如果您觉得 members 需要自己的 location 参数,那么这意味着两个位置输入可能不同。如果它们可以不同,则应将它们表示为两个单独的变量,以最大限度地提高灵活性和查询重用。

【讨论】:

这是一个很好的解释,谢谢!为前端开发人员提供灵活性也是我喜欢选项 1 和 3 的原因。一件事-您的示例与选项1不同吗?感谢您在层次结构/约束方面的解释,这很有帮助! 不,再看两个例子。在我的 sn-p 中,players 仍然采用名为 playerInput 的单个参数——不同之处在于我们不是提供单个变量,而是构造对象并为其字段提供多个变量。我并不是说这一定更好,但是如果您决定只提供位置,这是一种方法而不像在第一个 sn-p 中那样更改字段以接受多个参数. 我再次查看了它们,它们是相同的 - 在示例 1 中,query 采用多个参数,但 players 采用单个 playerInput 参数,由传递给查询的参数构造而成。 (我编辑了该示例,因为之前它使用了 isActive 参数,但没有进行任何其他更改)。再次感谢您的解释!

以上是关于GraphQL:在同一查询中使用输入类型及其字段之一的主要内容,如果未能解决你的问题,请参考以下文章

在 GraphQL 中不能有带有嵌套字段的输入类型。错误:预期类型是 GraphQLInputType,但不是

GraphQL:每种类型的子字段与可以使用 args 过滤的根查询字段?

GraphQL 错误:输入类型中未定义字段

如何处理 GraphQL 中的嵌套输入

如何使用 GraphQL 查询 Wordpress 关系字段?

GraphQL 响应类型/片段之争