通常我们在前端代码中定义查询。如果不这样做,如何让服务器决定发送什么?
spec
,GraphQL执行请求必须包括两个部分:1)模式;以及2)包含操作定义的文档。操作定义确定要执行的操作(哪个查询或变异)以及响应的格式。有变通方法和例外(我将在下面讨论一些),但是,一般来说,
如果指定客户端上的响应的形状是不可取的或某种不可能的,那么您应该仔细考虑GraphQL是否是您需要的正确解决方案。
除此之外,GraphQL更适合于单个请求,而不是现有restapi所需的一系列结构化请求。所以答案看起来更像这样:
[
{
title: 'News',
content: [
...
],
},
{
title: 'Photos',
content: [
...
],
}
]
相应的查询可能如下所示:
query HomePageContent {
blocks {
title
content {
# additional fields
}
}
}
content
. 这通常通过使用接口或联合将多个类型聚合为单个抽象类型来解决。模式的确切结构将取决于您发送的数据,但下面是一个示例:
interface BlockContentItem {
id: ID!
url: String!
}
type Story implements BlockContentItem {
id: ID!
url: String!
author: String!
title: String!
}
type Image implement BlockContentItem {
id: ID!
url: String!
alt: String!
}
type Block {
title: String!
content: [BlockContentItem!]!
}
type Query {
blocks: [Block!]!
}
您现在可以查询
blocks
query HomePageContent {
blocks {
title
content {
# these fields apply to all BlockContentItems
__typename
id
url
# then we use inline fragments to specify type-specific fields
... on Image {
alt
}
... on Story {
author
title
}
}
}
}
__typename
识别给定对象的类型,这可能对客户端应用程序有帮助(像Apollo这样的客户端会自动包含此字段)。
当然,当您想添加一个新的块时,仍然有一个问题。如果块的内容符合现有类型,则无需担心。但是,如果你预期将来需要一种不同的类型,但现在却不能围绕着它进行设计,会发生什么呢?
通常,这种更改需要服务器上的模式更改和客户端上的查询更改。而且在
,这可能很好,因为如果您使用不同的结构获取数据,
. 否则,您的应用程序将不知道如何正确呈现新的数据结构。
-
而不是为
内容
,只需使用自定义的JSON标量。这将有效地抛出响应验证窗口,但它将允许您为给定块的内容返回所需的任何内容。
-
将将来可能需要的任何字段抽象为某种值键类型。例如:
type MetaItem {
key: String!
value: String!
}
type Block {
title: String!
meta: [MetaItem!]!
# other common fields
}