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

时间:2015-12-10 10:50:44

标签: 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'
            ]

        ];
    }

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

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

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

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

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

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

6 个答案:

答案 0 :(得分:55)

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

答案 1 :(得分:53)

是的,您可以使用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命令使用内省来生成类型。

答案 2 :(得分:24)

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

fragment UserFragment on Users {
    id
    username
    count
} 

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

答案 3 :(得分:6)

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

答案 4 :(得分:0)

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

答案 5 :(得分: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
    )
)