如何在不编写长查询的情况下查询所有GraphQL类型字段?

Bla*_*gma 93 php laravel graphql graphql-php

假设您有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'
            ]

        ];
    }
Run Code Online (Sandbox Code Playgroud)

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

FetchUsers{users(id:"2"){id,username,count}}
Run Code Online (Sandbox Code Playgroud)

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

FetchUsers{users(id:"2"){*}}
//or
FetchUsers{users(id:"2")}
Run Code Online (Sandbox Code Playgroud)

有没有办法在GraphQL中执行此操作?

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

Pet*_*rne 79

不幸的是,你不想做什么.GraphQL要求您明确指定要从查询中返回的字段.

  • @meandre,graphql的整个想法是没有"unkown form"这样的东西. (14认同)
  • @s.meijer 纸面上的一切都非常好。但在现实世界中,开发人员只需请求整个事情,然后查看键和值即可快速了解什么是可能的,什么是不可能的。GraphQL 需要以这种方式更仔细地考虑文档,有时对于相对良性的事情。同样非常烦人的是,如果您需要所有或大多数属性,您仍然必须枚举它们*全部*才能检索信息。看起来灵感来自于 SQL,但遗漏了重要的部分。考虑“选择*” (12认同)
  • 好的,如果我从后端请求一些未知形式的对象,我应该代理或发回? (3认同)
  • @meandre,我的回答可能对你有用吗? (2认同)
  • 有趣的是,使用 graphql 时确实有不同的心态 (2认同)
  • 虽然准确,但这不是一个非常有用的答案。提供有关此主题的官方文档的链接和摘录至少会有所帮助。 (2认同)

Mar*_*ian 67

是的,你可以使用内省做到这一点.创建一个GraphQL查询(对于UserType类型)

{
   __type(name:"UserType") {
      fields {
         name
         description
      }  
   }
}
Run Code Online (Sandbox Code Playgroud)

并且你会得到一个响应(实际的字段名称将取决于你的实际架构/类型定义)

{
  "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. ...)
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

这取决于您知道要获取字段的类型的名称 - 如果您不知道类型,您可以使用内省来获取所有类型和字段

{
  __schema {
    types {
      name
      fields {
        name
        description
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

注意:这是线上的GraphQL数据 - 您可以自己决定如何使用实际客户端进行读写.您的graphQL javascript库可能已经在某种程度上使用了内省,例如apollo codegen命令使用内省来生成类型.

  • 根据答案,您必须根据第一个查询的结果动态构建第二个查询 - 我将其作为练习留给读者。 (6认同)
  • 上面的答案只允许您查询查询中可用的字段类型。它不会返回所有对象字段“值”,这就是原始问题的内容。 (2认同)

tom*_*mmy 28

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

fragment UserFragment on Users {
    id
    username
    count
} 

FetchUsers {
    users(id: "2") {
        ...UserFragment
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果我这样做,那么我仍然必须写"每个字段名称至少在片段中",这是我试图避免的,似乎GraphQL迫使我们明确. (15认同)
  • @JPVentura:不,我的朋友,可重用性和通配符在概念和应用程序上都有区别。文档中明确了片段的用途“GraphQL 包括称为片段的可重用单元”。使用片段很有用,但不是问题的答案。 (6认同)

Tyr*_*son 7

当我需要从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
Run Code Online (Sandbox Code Playgroud)

然后我用它来做我们的对象

field :location, Types::JsonType
Run Code Online (Sandbox Code Playgroud)

我会非常谨慎地使用它,只在你知道你总是需要整个JSON对象的地方使用它(正如我在我的情况下所做的那样).否则它更普遍地说是打败了GraphQL的对象.

  • 这正是我需要的,谢谢。我的用例是我在整个系统中都有用户可翻译的字符串,它们作为 json 存储在数据库中,如 `{"en": "Hello", "es": "Hola"}`。而且由于每个用户都可以为他们的用例实现他们自己的语言子集,因此 UI 查询每个可能的子集是没有意义的。你的例子很完美。 (2认同)
  • “否则,更一般地说,它就违背了 GraphQL 的目标。”谁在乎呢? (2认同)

JP *_*ura 6

GraphQL 查询格式旨在允许:

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

但是,根据GraphQL 文档,您可以创建片段以使选择集更可重用:

# Only most used selection properties

fragment UserDetails on User {
    id,
    username
} 
Run Code Online (Sandbox Code Playgroud)

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

FetchUsers {
    users() {
        ...UserDetails
    }
}
Run Code Online (Sandbox Code Playgroud)

您还可以在片段旁边添加其他字段

FetchUserById($id: ID!) {
    users(id: $id) {
        ...UserDetails
        count
    }
}
Run Code Online (Sandbox Code Playgroud)