Урок 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-запрос преобразует этот ответ:
- Добавляет 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-запросе директива @underEachArrayItem (предоставляемая расширением Field Value Iteration and Manipulation) является компонуемой директивой. При первом использовании она вкладывает только одну директиву, и аргумент affectDirectivesUnderPos можно опустить:
@underEachArrayItem
@underJSONObjectProperty(
# ...
)(Кстати, обратите внимание, что @underJSONObjectProperty тоже является компонуемой директивой, вкладывающей директиву @default).
При втором использовании она вкладывает 4 директивы справа от неё, что указано аргументом affectDirectivesUnderPos со значением [1, 2, 3, 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-запрос выводит только адреса электронной почты из ответа API, извлекая свойство email из каждой записи и заменяя им значение поля:
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-запрос извлекает адреса электронной почты из ответа 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:)) динамическую переменную, вычисленную для запрашиваемого объекта, логика будет выполняться или нет в зависимости от условий, относящихся к этой сущности.
Таким образом, можно динамически изменять ответ для одних сущностей (и не изменять для других) в зависимости от таких условий, как:
- Есть ли у записи комментарии?
- Есть ли у комментария ответы?
- Является ли пользователь администратором?
- Применён ли тег/категория к какой-либо записи?
- И т.д.