如何在不编写长查询的情况下查询所有 GraphQL 类型字段?
Posted
技术标签:
【中文标题】如何在不编写长查询的情况下查询所有 GraphQL 类型字段?【英文标题】:How to query all the GraphQL type fields without writing a long query? 【发布时间】:2020-02-26 01:52:37 【问题描述】:假设您有一个 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'
]
];
查询所有字段通常是这样的:
FetchUsersusers(id:"2")id,username,count
但我想要一种无需编写所有字段即可获得相同结果的方法,如下所示:
FetchUsersusers(id:"2")*
//or
FetchUsersusers(id:"2")
有没有办法在 GraphQL 中做到这一点??
我正在使用 Folkloreatelier/laravel-graphql 库。
【问题讨论】:
你在问如何做一些 GraphQL 在设计上不支持的事情。 不支持它是有道理的,假设您有 Student 和 Class 对象,student 有字段“classes”列出他参加的所有课程,class 有字段“students”列出所有参加的学生那堂课。那是一个循环结构。现在,如果您要求所有学生的所有字段,那是否还包括返回的所有课程字段?那些班有学生,他们的领域也包括在内吗?学生们上课,... 我有这个问题,它是为了让我可以看到什至可以拉出什么。许多 GraphQL 客户端(例如 GraphiQL,请参阅 gatsbyjs.org/docs/running-queries-with-graphiql)都有一个模式浏览器,它使用内省向您展示您可以提取的内容,如果这就是想要获得“一切”的原因的话。 这里是讨论:github.com/graphql/graphql-spec/issues/127 【参考方案1】:很遗憾,您想做的事情是不可能的。 GraphQL 要求您明确指定希望从查询中返回的字段。
【讨论】:
好的,如果我从后端请求一些未知形式的对象,我应该代理或发回? @meandre,graphql 的整体理念是没有“未知形式”这样的东西。 @meandre,我下面的回答可能对你有用吗? 有意思,用graphql真的是不一样的心态 虽然准确,但这不是一个非常有用的答案。提供有关此主题的官方文档的链接和摘录至少会有所帮助。【参考方案2】:是的,您可以使用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 属性 - 他已经知道了,因为这正是他在之前的查询中提出的问题。【参考方案3】:我想这样做的唯一方法是利用可重复使用的片段:
fragment UserFragment on Users
id
username
count
FetchUsers
users(id: "2")
...UserFragment
【讨论】:
如果我这样做了,那么我仍然必须“至少在片段中”写下每个字段名称,这与我试图避免的事情相比,似乎 GraphQL 迫使我们变得明确。跨度> 如何在 POSTMan 查询中添加这个?或 jquery/UI 框架来制作字符串化的 JSON 。这个 graphiQL 似乎对实际开发目的毫无用处。 这仅供重复使用。 @BlackSigma 考虑到GraphQL documentation,这应该是公认的最佳答案 @JPVentura:不,我的朋友,可重用性和通配符在概念和应用上都有区别。文档“GraphQL 包括称为片段的可重用单元”中明确了片段的用途。使用片段很有用,但不是问题的答案。【参考方案4】:当我需要从 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 查询每个可能的子集是没有意义的。您的示例完美运行。【参考方案5】:
GraphQL query format 旨在允许:
-
查询和结果形状完全相同。
服务器确切地知道所请求的字段,因此客户端只下载基本数据。
但是,根据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
)
)
【讨论】:
以上是关于如何在不编写长查询的情况下查询所有 GraphQL 类型字段?的主要内容,如果未能解决你的问题,请参考以下文章
Gatsby + Contentful - 如何在不重新启动服务器的情况下在本地重做 GraphQL 查询(npm run dev)?
GraphQL 是不是适合在不进行多次查询的情况下从后端检索多级 facet 数据?
我可以在不使用 prisma 的情况下在我的 graphQL 服务器中使用 MongoDB 吗?