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


当前回答

当我需要从谷歌places API加载已序列化到数据库中的位置数据时,我也遇到了同样的问题。一般来说,我想要整个东西,这样它就能与map一起工作,但我不想每次都必须指定所有字段。

我在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的对象。

其他回答

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

是的,您可以使用自省来做到这一点。创建一个像这样的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命令使用自省来生成类型。

2022年更新

由于这个答案最初是这样写的,所以现在建议在生产中关闭自省。参考:为什么应该在生产环境中禁用GraphQL自省。

对于在生产环境中关闭内省的环境,您可以在开发中使用它作为一种方式来帮助创建在生产中使用的静态查询;实际上,您无法在生产环境中动态地创建查询。

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

fragment UserFragment on Users {
    id
    username
    count
} 

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

GraphQL查询格式的设计是为了允许:

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

然而,根据GraphQL文档,你可以创建片段,以使选择集更可重用:

# Only most used selection properties

fragment UserDetails on User {
    id,
    username
} 

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

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

你也可以在片段旁边添加其他字段:

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

当我需要从谷歌places API加载已序列化到数据库中的位置数据时,我也遇到了同样的问题。一般来说,我想要整个东西,这样它就能与map一起工作,但我不想每次都必须指定所有字段。

我在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的对象。