【问题标题】:How to query all the GraphQL type fields without writing a long query?如何在不编写长查询的情况下查询所有 GraphQL 类型字段?
【发布时间】:2020-08-19 05:38:03
【问题描述】:

假设您有一个 GraphQL 类型,它包含许多字段。 如何在不写下包含所有字段名称的长查询的情况下查询所有字段?

例如,如果我有这些字段:

 public function fields()
    {
        return [
            'id' => [
                'type' => Type::nonNull(Type::string()),
                'description' => 'The id of the user'
            ],
            'username' => [
                'type' => Type::string(),
                'description' => 'The email of user'
            ], 
             'count' => [
                'type' => Type::int(),
                'description' => 'login count for the user'
            ]

        ];
    }

查询所有字段通常是这样的:

FetchUsers{users(id:"2"){id,username,count}}

但我想要一种无需编写所有字段即可获得相同结果的方法,如下所示:

FetchUsers{users(id:"2"){*}}
//or
FetchUsers{users(id:"2")}

有没有办法在 GraphQL 中做到这一点??

我正在使用 Folkloreatelier/laravel-graphql 库。

【问题讨论】:

  • 你在问如何做一些 GraphQL 在设计上不支持的事情。
  • 不支持它是有道理的,假设您有 Student 和 Class 对象,student 有字段“classes”列出他参加的所有课程,class 有字段“students”列出所有参加的学生那堂课。那是一个循环结构。现在,如果您要求所有学生的所有字段,那是否还包括返回的所有课程字段?那些班有学生,他们的领域也包括在内吗?学生们上课,...
  • 我有这个问题,它是为了让我可以看到什至可以拉出什么。许多 GraphQL 客户端(例如 GraphiQL,请参阅 gatsbyjs.org/docs/running-queries-with-graphiql)都有一个模式浏览器,它使用内省向您展示您可以提取的内容,如果这就是想要获得“一切”的原因的话。

标签: php laravel graphql graphql-php


【解决方案1】:

我想这样做的唯一方法是利用可重复使用的片段:

fragment UserFragment on Users {
    id
    username
    count
} 

FetchUsers {
    users(id: "2") {
        ...UserFragment
    }
}

【讨论】:

  • 如果我这样做了,那么我仍然必须“至少在片段中”写下每个字段名称,这与我试图避免的事情相比,似乎 GraphQL 迫使我们变得明确。跨度>
  • 如何在 POSTMan 查询中添加这个?或 jquery/UI 框架来制作字符串化的 JSON 。这个 graphiQL 似乎对实际开发目的毫无用处。
  • 这仅供重复使用。
  • @BlackSigma 考虑到GraphQL documentation,这应该是公认的最佳答案
  • @JPVentura:不,我的朋友,可重用性和通配符在概念和应用上都有区别。文档“GraphQL 包括称为片段的可重用单元”中明确了片段的用途。使用片段很有用,但不是问题的答案。
【解决方案2】:

很遗憾,您想做的事情是不可能的。 GraphQL 要求您明确指定希望从查询中返回的字段。

【讨论】:

  • 好的,如果我从后端请求一些未知形式的对象,我应该代理或发回?
  • @meandre,graphql 的整个想法是没有“未知形式”这样的东西。
  • @meandre,我下面的回答可能对你有用吗?
  • 有意思,用graphql真的是不一样的心态
  • 虽然准确,但这不是一个非常有用的答案。提供有关此主题的官方文档的链接和摘录至少会有所帮助。
【解决方案3】:

当我需要从 google Places API 加载已序列化到数据库中的位置数据时,我遇到了同样的问题。一般来说,我想要整个东西,所以它可以与地图一起使用,但我不想每次都指定所有字段。

我是用 Ruby 工作的,所以我不能给你 PHP 的实现,但原理应该是一样的。

我定义了一个名为 JSON 的自定义标量类型,它只返回一个文字 JSON 对象。

ruby 实现是这样的(使用 graphql-ruby)

module Graph
  module Types
    JsonType = GraphQL::ScalarType.define do
      name "JSON"
      coerce_input -> (x) { x }
      coerce_result -> (x) { x }
    end
  end
end

然后我像这样将它用于我们的对象

field :location, Types::JsonType

不过,我会非常谨慎地使用它,仅在您知道您总是需要整个 JSON 对象的情况下使用它(就像我在我的例子中所做的那样)。否则更笼统地说,它正在击败 GraphQL 的对象。

【讨论】:

  • 这正是我所需要的,谢谢。我的用例是我在整个系统中都有用户可翻译的字符串,它们以 json 格式存储在数据库中,如{"en": "Hello", "es": "Hola"}。而且由于每个用户都可以为他们的用例实现他们自己的语言子集,因此 UI 查询每个可能的子集是没有意义的。您的示例完美运行。
【解决方案4】:

是的,您可以使用introspection 执行此操作。进行类似的 GraphQL 查询(对于 UserType 类型)

{
   __type(name:"UserType") {
      fields {
         name
         description
      }  
   }
}

您会得到类似的响应(实际字段名称将取决于您的实际架构/类型定义)

{
  "data": {
    "__type": {
      "fields": [
        {
          "name": "id",
          "description": ""
        },
        {
          "name": "username",
          "description": "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only."
        },
        {
          "name": "firstName",
          "description": ""
        },
        {
          "name": "lastName",
          "description": ""
        },
        {
         "name": "email",
          "description": ""
        },
        ( etc. etc. ...)
      ]
    }
  }
}

然后,您可以在客户端中读取此字段列表并动态构建第二个 GraphQL 查询以获取所有这些字段的值。

这取决于您知道要为其获取字段的类型的名称——如果您不知道类型,您可以使用内省将所有类型和字段放在一起

{
  __schema {
    types {
      name
      fields {
        name
        description
      }
    }
  }
}

注意:这是无线 GraphQL 数据——您需要自己弄清楚如何使用您的实际客户端进行读写。您的 graphQL javascript 库可能已经在某些方面使用了自省,例如 apollo codegen 命令使用自省来生成类型。

【讨论】:

  • 似乎应该表达对递归类型的关心。如果你从树上下来并碰到一个包含自身的类型,以某种形式(列表、单个或其他......),你可能会陷入无限递归。
  • 根据我对这个特定查询的经验,这实际上并没有发生——查询本身定义了分辨率深度。
  • 以上答案只允许您查询查询中可用的字段类型。它不会返回所有对象字段“值”,这就是原始问题的含义。
  • 根据答案,您必须根据第一个查询的结果动态构建第二个查询——我把它留给读者作为练习。
  • 进行练习的用户会发现 UserType 类型有一个属性 fields,它是一个包含 name 的对象数组description 属性 - 他已经知道了,因为这正是他在之前的查询中提出的问题。
【解决方案5】:

GraphQL query format 旨在允许:

  1. 查询和结果形状完全相同
  2. 服务器确切地知道所请求的字段,因此客户端只下载基本数据。

但是,根据GraphQL documentation,您可以创建fragments 以使选择集更可重用:

# Only most used selection properties

fragment UserDetails on User {
    id,
    username
} 

然后您可以通过以下方式查询所有用户详细信息:

FetchUsers {
    users() {
        ...UserDetails
    }
}

你也可以add additional fields alongside your fragment:

FetchUserById($id: ID!) {
    users(id: $id) {
        ...UserDetails
        count
    }
}

【讨论】:

    【解决方案6】:

    包 graphql-type-json 支持自定义标量类型 JSON。 使用它可以显示您的 json 对象的所有字段。 这是 ApolloGraphql Server 中示例的链接。 https://www.apollographql.com/docs/apollo-server/schema/scalars-enums/#custom-scalars

    【讨论】:

      【解决方案7】:

      哈哈,我前一天发布的框架可以解决你的问题

      https://github.com/babyfish-ct/graphql-ts-client

      长查询:

      const employees = findEmployees(
          {}, 
          employee$.
          .id
          .firstName
          .lastName
          .gender
          .salary
          .subordinates(
              employee$.id
          )
      )
      
      

      短查询(employee$$ = employee$ + 所有标量字段):

      const employees = findEmployees(
          {}, 
          employee$$.
          .subordinates(
              employee$.id
          )
      )
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-07-12
        • 2018-06-27
        • 2022-01-03
        • 1970-01-01
        相关资源
        最近更新 更多