Schema 教程第5课:为不同用户定制内容
第5课:为不同用户定制内容
我们可以根据查询到的数据(例如登录用户的角色),在字段中返回不同的响应。
为不同用户定制内容的 GraphQL Query
以下 GraphQL query 用于获取文章内容,并仅为管理员用户在内容底部追加"编辑此文章"链接:
query InitializeDynamicVariables
@configureWarningsOnExportingDuplicateVariable(enabled: false)
{
isAdminUser: _echo(value: false)
@export(as: "isAdminUser")
@remove
}
query ExportConditionalVariables
@depends(on: "InitializeDynamicVariables")
{
me {
roleNames @remove
isAdminUser: _inArray(
value: "administrator",
array: $__roleNames
)
@export(as: "isAdminUser")
}
}
query RetrieveContentForAdminUser($postId: ID!)
@depends(on: "ExportConditionalVariables")
@include(if: $isAdminUser)
{
post(by: { id : $postId }) {
originalContent: content @remove
wpAdminEditURL @remove
content: _sprintf(
string: "%s<p><a href=\"%s\">%s</a></p>",
values: [
$__originalContent,
$__wpAdminEditURL,
"(Admin only) Edit post"
]
)
}
}
query RetrieveContentForNonAdminUser($postId: ID!)
@depends(on: "ExportConditionalVariables")
@skip(if: $isAdminUser)
{
post(by: { id : $postId }) {
content
}
}
query ExecuteAll
@depends(on: [
"RetrieveContentForAdminUser",
"RetrieveContentForNonAdminUser"
])
{
id @remove
}对于管理员用户,响应如下:
{
"data": {
"user": {
"isAdminUser": true
},
"post": {
"content": "\n<p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!<\/p>\n<p><a href=\"https:\/\/mysite.com\/wp-admin\/post.php?post=1&action=edit\">(Admin only) Edit post<\/a><\/p>"
}
}
}对于非管理员用户,响应如下:
{
"data": {
"user": {
"isAdminUser": false
},
"post": {
"content": "\n<p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!<\/p>\n"
}
}
}让 GraphQL 服务器(在所有可能的条件下)动态计算字段所需的值,具有以下优势:
- 简化应用程序逻辑:建立单一可信来源,代码变得 DRY,客户端无需再实现对应的逻辑
- 提升应用程序可靠性:当多个客户端访问服务器数据时,同一逻辑的不同实现可能存在差异,从而导致 bug(尤其是当客户端基于不同技术时,例如网站用 JavaScript、Android 应用用 Java、iPhone 应用用 Swift 等)
逐步解析:创建 GraphQL Query
以下是对该 query 工作原理的详细分析。
判断用户是否为管理员
该 query 检查登录用户是否具有 "administrator" 角色,并将此条件导出到动态变量 $isAdminUser:
query
{
me {
roleNames
isAdminUser: _inArray(
value: "administrator",
array: $__roleNames
)
@export(as: "isAdminUser")
}
}操作的条件执行
当 Multiple Query Execution 启用时,指令 @include 和 @skip 也可以应用于操作。这样,我们就可以根据某个动态变量的值来决定是否执行某个操作。
在以下 query 中,两个操作中只有一个会被执行:
RetrieveContentForAdminUser仅在$isAdminUser为true时执行RetrieveContentForNonAdminUser仅在$isAdminUser为false时执行
query RetrieveContentForAdminUser
@depends(on: "ExportConditionalVariables")
@include(if: $isAdminUser)
{
# ...
}
query RetrieveContentForNonAdminUser
@depends(on: "ExportConditionalVariables")
@skip(if: $isAdminUser)
{
# ...
}我们来为文章的 content 字段根据用户是否为管理员提供两种不同的响应:
- 第一个操作将
content用作别名,通过_sprintf将originalContent字段和wpAdminEditURL字段拼接在一起,动态计算字段值 - 第二个操作直接获取
content字段
query RetrieveContentForAdminUser($postId: ID!)
@depends(on: "ExportConditionalVariables")
@include(if: $isAdminUser)
{
post(by: { id : $postId }) {
originalContent: content
wpAdminEditURL
content: _sprintf(
string: "%s<p><a href=\"%s\">%s</a></p>",
values: [
$__originalContent,
$__wpAdminEditURL,
"(Admin only) Edit post"
]
)
}
}
query RetrieveContentForNonAdminUser($postId: ID!)
@depends(on: "ExportConditionalVariables")
@skip(if: $isAdminUser)
{
post(by: { id : $postId }) {
content
}
}添加待执行的操作
现在我们有了两个可能被执行的操作,但在执行 query 时只能指定一个 ?operationName=...。
因此,我们添加操作 ExecuteAll,使其同时依赖于 RetrieveContentForAdminUser 和 RetrieveContentForNonAdminUser,并包含简单字段 id(因为操作中必须查询某些内容):
query ExecuteAll
@depends(on: [
"RetrieveContentForAdminUser",
"RetrieveContentForNonAdminUser"
])
{
id
}使用 ?operationName=ExecuteAll 调用端点时,两个操作都会被加载,但实际只有其中一个会被执行。
移除不需要的数据
最后一步是通过 @remove 移除所有辅助字段(即不需要在响应中输出的字段)。
完整的 GraphQL query 如下:
query InitializeDynamicVariables
@configureWarningsOnExportingDuplicateVariable(enabled: false)
{
isAdminUser: _echo(value: false)
@export(as: "isAdminUser")
@remove
}
query ExportConditionalVariables
@depends(on: "InitializeDynamicVariables")
{
me {
roleNames @remove
isAdminUser: _inArray(
value: "administrator",
array: $__roleNames
)
@export(as: "isAdminUser")
}
}
query RetrieveContentForAdminUser($postId: ID!)
@depends(on: "ExportConditionalVariables")
@include(if: $isAdminUser)
{
post(by: { id : $postId }) {
originalContent: content @remove
wpAdminEditURL @remove
content: _sprintf(
string: "%s<p><a href=\"%s\">%s</a></p>",
values: [
$__originalContent,
$__wpAdminEditURL,
"(Admin only) Edit post"
]
)
}
}
query RetrieveContentForNonAdminUser($postId: ID!)
@depends(on: "ExportConditionalVariables")
@skip(if: $isAdminUser)
{
post(by: { id : $postId }) {
content
}
}
query ExecuteAll
@depends(on: [
"RetrieveContentForAdminUser",
"RetrieveContentForNonAdminUser"
])
{
id @remove
}Prev
Next