如何从服务器加载graphql查询而不在前端定义它?
现在让我们假设我们正在使用RESTAPI。我有这样一个端点:如何从服务器加载graphql查询而不在前端定义它?,graphql,apollo,Graphql,Apollo,现在让我们假设我们正在使用RESTAPI。我有这样一个端点:/homeNewsFeed。此API将为我们提供如下响应: [ { blockTitle: 'News', type: 'list', api: 'http://localhost/news' }, { blockTitle: 'Photos', type: 'gallery', api: 'http://localhost/gallery' } ] [ {
/homeNewsFeed
。此API将为我们提供如下响应:
[
{
blockTitle: 'News',
type: 'list',
api: 'http://localhost/news'
},
{
blockTitle: 'Photos',
type: 'gallery',
api: 'http://localhost/gallery'
}
]
[
{
title: 'News',
content: [
...
],
},
{
title: 'Photos',
content: [
...
],
}
]
query HomePageContent {
blocks {
title
content {
# additional fields
}
}
}
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
}
}
}
}
现在,在获得这些信息之后,我们将遍历数组并调用相应的端点来加载数据。我的问题是,如何在GraphQL中实现这一点?通常我们在前端代码中定义查询。如果不这样做,如何让服务器决定发送什么
这样做的主要原因是。假设我们有一个移动应用程序。我们需要在不发送应用程序更新的情况下将新块推送到此新闻提要。但每个项目都可以有自己的查询
通常我们在前端代码中定义查询。如果不这样做,如何让服务器决定发送什么
根据,GraphQL执行请求必须包括两件事:1)模式;以及2)包含操作定义的文档。操作定义确定要执行的操作(哪个查询或变异)以及响应的格式。有一些工作和例外(我将在下面讨论),但是,一般来说,<强>如果在客户端指定响应的形状是不可取的或某种不可能的,那么你应该仔细考虑GraphQL是否是你的需求>/P>的正确解决方案。
除此之外,GraphQL更适合于单个请求,而不是像您现有的RESTAPI所需要的一系列结构化请求。因此,响应看起来更像这样:
[
{
blockTitle: 'News',
type: 'list',
api: 'http://localhost/news'
},
{
blockTitle: 'Photos',
type: 'gallery',
api: 'http://localhost/gallery'
}
]
[
{
title: 'News',
content: [
...
],
},
{
title: 'Photos',
content: [
...
],
}
]
query HomePageContent {
blocks {
title
content {
# additional fields
}
}
}
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
}
}
}
}
相应的查询可能如下所示:
[
{
blockTitle: 'News',
type: 'list',
api: 'http://localhost/news'
},
{
blockTitle: 'Photos',
type: 'gallery',
api: 'http://localhost/gallery'
}
]
[
{
title: 'News',
content: [
...
],
},
{
title: 'Photos',
content: [
...
],
}
]
query HomePageContent {
blocks {
title
content {
# additional fields
}
}
}
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
}
}
}
}
现在的问题是如何区分不同种类的内容。这通常通过使用接口或联合将多个类型聚合为单个抽象类型来解决。模式的确切结构取决于您发送的数据,但以下是一个示例:
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!]!
}
现在可以像这样查询块
:
[
{
blockTitle: 'News',
type: 'list',
api: 'http://localhost/news'
},
{
blockTitle: 'Photos',
type: 'gallery',
api: 'http://localhost/gallery'
}
]
[
{
title: 'News',
content: [
...
],
},
{
title: 'Photos',
content: [
...
],
}
]
query HomePageContent {
blocks {
title
content {
# additional fields
}
}
}
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
}
}
}
}
这样使用内联片段可以确保只为这些类型的实例返回特定于类型的字段。我加入了\uuuuTypeName
来识别给定对象的类型,这可能对客户端应用程序有帮助(像Apollo这样的客户端会自动包含此字段)
当然,当您想要添加一个新块时,仍然存在一个问题。如果块的内容符合现有类型,则无需担心。但是,如果您预计将来需要一种不同的类型,但现在不能围绕它进行设计,会发生什么呢
通常,这种更改需要服务器上的模式更改和客户端上的查询更改。在大多数情况下,,这可能是好的,因为如果你获取的数据是不同的结构,你无论如何都必须更新你的客户端应用程序。否则,您的应用程序将不知道如何正确呈现新的数据结构
但假设我们想对我们的模式进行未来验证。这里有两种方法可以让你做到这一点
不要为内容指定接口,只需使用自定义JSON标量即可。这将有效地将响应验证抛出窗口,但它将允许您为给定块的内容返回所需的任何内容
将将来可能需要的任何字段抽象为某种值键类型。例如:
还有很多其他的解决方法,根据您使用的数据类型,有些方法比其他方法更好。但希望这能让您了解如何在GraphQL上下文中处理所描述的场景
通常我们在前端代码中定义查询。如果不这样做,如何让服务器决定发送什么
根据,GraphQL执行请求必须包括两件事:1)模式;以及2)包含操作定义的文档。操作定义确定要执行的操作(哪个查询或变异)以及响应的格式。有一些工作和例外(我将在下面讨论),但是,一般来说,<强>如果在客户端指定响应的形状是不可取的或某种不可能的,那么你应该仔细考虑GraphQL是否是你的需求>/P>的正确解决方案。
除此之外,GraphQL更适合于单个请求,而不是像您现有的RESTAPI所需要的一系列结构化请求。因此,响应看起来更像这样:
[
{
blockTitle: 'News',
type: 'list',
api: 'http://localhost/news'
},
{
blockTitle: 'Photos',
type: 'gallery',
api: 'http://localhost/gallery'
}
]
[
{
title: 'News',
content: [
...
],
},
{
title: 'Photos',
content: [
...
],
}
]
query HomePageContent {
blocks {
title
content {
# additional fields
}
}
}
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
}
}
}
}
相应的查询可能如下所示:
[
{
blockTitle: 'News',
type: 'list',
api: 'http://localhost/news'
},
{
blockTitle: 'Photos',
type: 'gallery',
api: 'http://localhost/gallery'
}
]
[
{
title: 'News',
content: [
...
],
},
{
title: 'Photos',
content: [
...
],
}
]
query HomePageContent {
blocks {
title
content {
# additional fields
}
}
}
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
}
}
}
}
现在的问题是如何区分不同种类的内容。这通常通过使用接口或联合将多个类型聚合为单个抽象类型来解决。模式的确切结构取决于您发送的数据,但以下是一个示例:
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!]!
}
现在可以像这样查询块
:
[
{
blockTitle: 'News',
type: 'list',
api: 'http://localhost/news'
},
{
blockTitle: 'Photos',
type: 'gallery',
api: 'http://localhost/gallery'
}
]
[
{
title: 'News',
content: [
...
],
},
{
title: 'Photos',
content: [
...
],
}
]
query HomePageContent {
blocks {
title
content {
# additional fields
}
}
}
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
}
}
}
}
这样使用内联片段可以确保只为这些类型的实例返回特定于类型的字段。我加入了\uuuuTypeName
来识别给定对象的类型,这可能对客户端应用程序有帮助(像Apollo这样的客户端会自动包含此字段)
当然,当您想要添加一个新块时,仍然存在一个问题。如果块的内容符合现有类型,则无需担心。但是,如果您预计将来需要一种不同的类型,但现在不能围绕它进行设计,会发生什么呢
通常,这种更改需要服务器上的模式更改和客户端上的查询更改。在大多数情况下,,这可能是好的,因为如果你获取的数据是不同的结构,你无论如何都必须更新你的客户端应用程序。否则,您的应用程序将不知道如何正确呈现新的数据结构
但假设我们想对我们的模式进行未来验证。这里有两种方法可以让你做到这一点
Ins