第25课:转换外部 API 的数据
本教程课程通过示例演示如何将外部 API 的响应适配为所需的任意格式。
为每个条目添加默认值和额外属性
REST API 端点 newapi.getpop.org/wp-json/wp/v2/users/?_fields=id,name,url 返回用户数据,其中部分用户的 url 属性为空:
[
{
"id": 1,
"name": "leo",
"url": "https://leoloso.com"
},
{
"id": 7,
"name": "Test",
"url": ""
},
{
"id": 2,
"name": "Theme Demos",
"url": ""
}
]以下 GraphQL query 对该响应进行转换:
- 为
url属性为空的用户添加默认 URL - 为每个用户条目添加
link属性(由用户的姓名和 URL 值组合而成)
query {
# Retrieve data from the external API
usersWithLinkAndDefaultURL: _sendJSONObjectCollectionHTTPRequest(
input: {
url: "https://newapi.getpop.org/wp-json/wp/v2/users/?_fields=id,name,url"
}
)
# Set a default URL for users without any
@underEachArrayItem
@underJSONObjectProperty(
by: {
key: "url"
}
)
@default(
value: "https://mysite.com"
condition: IS_EMPTY
)
# Add a new "link" entry on the JSON object
@underEachArrayItem(
affectDirectivesUnderPos: [1, 2, 3, 4],
passValueOnwardsAs: "userListItem"
)
@applyField(
name: "_objectProperty",
arguments: {
object: $userListItem,
by: {
key: "name"
}
},
passOnwardsAs: "userName"
)
@applyField(
name: "_objectProperty",
arguments: {
object: $userListItem,
by: {
key: "url"
}
},
passOnwardsAs: "userURL"
)
@applyField(
name: "_sprintf",
arguments: {
string: "<a href=\"%s\">%s</a>",
values: [$userURL, $userName]
},
passOnwardsAs: "userLink"
)
@applyField(
name: "_objectAddEntry",
arguments: {
object: $userListItem,
key: "link",
value: $userLink
},
setResultInResponse: true
)
}响应如下:
{
"data": {
"usersWithLinkAndDefaultURL": [
{
"id": 1,
"name": "leo",
"url": "https://leoloso.com",
"link": "<a href=\"https://leoloso.com\">leo</a>"
},
{
"id": 7,
"name": "Test",
"url": "https://mysite.com",
"link": "<a href=\"https://mysite.com\">Test</a>"
},
{
"id": 2,
"name": "Theme Demos",
"url": "https://mysite.com",
"link": "<a href=\"https://mysite.com\">Theme Demos</a>"
}
]
}
}可组合指令可以在其中嵌套一个或多个指令。当嵌套多个指令时,需通过参数 affectDirectivesUnderPos 来指定,该参数包含从该指令到其嵌套指令的相对位置。
在上面的 GraphQL query 中,指令 @underEachArrayItem(由 Field Value Iteration and Manipulation 扩展提供)是一个可组合指令。在第一次出现时,它只嵌套了一个指令,因此可以省略参数 affectDirectivesUnderPos:
@underEachArrayItem
@underJSONObjectProperty(
# ...
)(顺便提一下,@underJSONObjectProperty 也是一个可组合指令,它嵌套了 @default 指令。)
在第二次出现时,通过将参数 affectDirectivesUnderPos 的值设为 [1, 2, 3, 4],它嵌套了右侧的 4 个指令:
@underEachArrayItem(
affectDirectivesUnderPos: [1, 2, 3, 4],
# ...
)
@applyField(
name: "_objectProperty",
# ...
)
@applyField(
name: "_objectProperty",
# ...
)
@applyField(
name: "_sprintf",
# ...
)
@applyField(
name: "_objectAddEntry",
# ...
)🔥 提示:
指令 @applyField(由 Field on Field 扩展提供)有两种输出目标:
- 指定参数
passOnwardsAs: "someVariableName"时,新值将被赋给动态变量$someVariableName,后续嵌套的指令可以读取该变量:
@applyField(
name: "_objectProperty",
arguments: {
object: $userListItem,
by: {
key: "name"
}
},
passOnwardsAs: "userName"
)- 指定参数
setResultInResponse: true时,新值将被重新赋给该字段(从而修改响应):
@applyField(
name: "_objectAddEntry",
arguments: {
object: $userListItem,
key: "link",
value: $userLink
},
setResultInResponse: true
)从 JSON 对象中提取特定属性
REST API 端点 newapi.getpop.org/wp-json/newsletter/v1/subscriptions 返回电子邮件订阅数据的集合,包括订阅者的邮箱地址和语言:
[
{
"email": "abracadabra@ganga.com",
"lang": "de"
},
{
"email": "longon@caramanon.com",
"lang": "es"
},
{
"email": "rancotanto@parabara.com",
"lang": "en"
},
{
"email": "quezarapadon@quebrulacha.net",
"lang": "fr"
},
{
"email": "test@test.com",
"lang": "de"
},
{
"email": "emilanga@pedrola.com",
"lang": "fr"
}
]以下 GraphQL query 通过从每个条目中提取 email 属性并替换字段值,仅输出 API 响应中的邮箱地址:
query {
emails: _sendJSONObjectCollectionHTTPRequest(
input: {
url: "https://newapi.getpop.org/wp-json/newsletter/v1/subscriptions"
}
)
@underEachArrayItem(
passValueOnwardsAs: "userEntry"
)
@applyField(
name: "_objectProperty"
arguments: {
object: $userEntry,
by: {
key: "email"
}
}
setResultInResponse: true
)
}响应如下:
{
"data": {
"emails": [
"abracadabra@ganga.com",
"longon@caramanon.com",
"rancotanto@parabara.com",
"quezarapadon@quebrulacha.net",
"test@test.com",
"emilanga@pedrola.com"
]
}
}有条件地修改字段值
本示例在上一个示例的基础上进一步演示,同时对响应中的邮箱地址格式进行转换。
以下 GraphQL query 从 API 响应中提取邮箱地址,并通过可组合指令 @if(由 Conditional Field Manipulation 扩展提供)将语言为英语或德语的用户邮箱地址转换为大写:
query {
# Retrieve data from a REST API endpoint
userEntries: _sendJSONObjectCollectionHTTPRequest(
input: {
url: "https://newapi.getpop.org/wp-json/newsletter/v1/subscriptions"
}
)
@remove
emails: _echo(value: $__userEntries)
# Iterate all the entries, passing every entry
# (under the dynamic variable $userEntry)
# to each of the next 4 directives
@underEachArrayItem(
passValueOnwardsAs: "userEntry"
affectDirectivesUnderPos: [1, 2, 3, 4]
)
# Extract property "lang" from the entry
# via the functionality field `_objectProperty`,
# and pass it onwards as dynamic variable $userLang
@applyField(
name: "_objectProperty"
arguments: {
object: $userEntry,
by: {
key: "lang"
}
}
passOnwardsAs: "userLang"
)
# Execute functionality field `_inArray` to find out
# if $userLang is either "en" or "de", and place the
# result under dynamic variable $isSpecialLang
@applyField(
name: "_inArray"
arguments: {
value: $userLang,
array: ["en", "de"]
}
passOnwardsAs: "isSpecialLang"
)
# Extract property "email" from the entry
# and set it back as the value for that entry
@applyField(
name: "_objectProperty"
arguments: {
object: $userEntry,
by: {
key: "email"
}
}
setResultInResponse: true
)
# If $isSpecialLang is `true` then execute
# directive `@strUpperCase`
@if(condition: $isSpecialLang)
@strUpperCase
}响应如下:
{
"data": {
"emails": [
"ABRACADABRA@GANGA.COM",
"longon@caramanon.com",
"RANCOTANTO@PARABARA.COM",
"quezarapadon@quebrulacha.net",
"TEST@TEST.COM",
"emilanga@pedrola.com"
]
}
}在 Gato GraphQL 中,条件逻辑的执行可以是动态的:通过将在被查询对象上求值的动态变量传递给 @if(condition:)(以及 @unless(condition:)),逻辑是否执行将取决于该实体的条件。
这样,我们可以基于以下条件,有选择地对部分实体动态修改响应:
- 文章是否有评论?
- 评论是否有回复?
- 用户是否为管理员?
- 标签/分类是否应用于某篇文章?
- 等等