255

假设您有一个 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库。

4

7 回答 7

249

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

于 2015-12-11T15:03:54.363 回答
163

是的,您可以使用自省来做到这一点。进行类似的 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命令使用自省来生成类型。

于 2017-05-31T15:36:08.340 回答
59

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

fragment UserFragment on Users {
    id
    username
    count
} 

FetchUsers {
    users(id: "2") {
        ...UserFragment
    }
}
于 2015-12-10T15:08:17.560 回答
17

当我需要从 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 的对象。

于 2017-01-15T12:52:16.037 回答
6

GraphQL 查询格式旨在允许:

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

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

# Only most used selection properties

fragment UserDetails on User {
    id,
    username
} 

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

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

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

FetchUserById($id: ID!) {
    users(id: $id) {
        ...UserDetails
        count
    }
}
于 2019-10-13T10:01:44.697 回答
0

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

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
    )
)

于 2021-06-22T18:43:57.003 回答
0

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

于 2020-01-20T17:01:32.437 回答