Урок 5: Настройка контента для разных пользователей
Мы можем получать различный ответ в поле в зависимости от некоторых запрошенных данных, например ролей авторизованного пользователя.
GraphQL-запрос для настройки контента для разных пользователей
Этот GraphQL-запрос получает содержимое записи и добавляет ссылку «Редактировать эту запись» в конец контента только для пользователя-администратора:
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, и клиентам больше не нужно реализовывать соответствующую логику
- Приложение становится более надёжным, особенно когда несколько клиентов обращаются к данным сервера, так как различные реализации одной и той же логики могут не совпадать, что потенциально приводит к ошибкам (тем более когда клиенты основаны на разных технологиях, например JavaScript для веб-сайта, Java для приложения Android, Swift для приложения iPhone и других)
Пошагово: создание GraphQL-запроса
Ниже приведён подробный анализ того, как работает запрос.
Определение того, является ли пользователь администратором
Этот запрос проверяет, имеет ли авторизованный пользователь роль "administrator", и экспортирует это условие в динамическую переменную $isAdminUser:
query
{
me {
roleNames
isAdminUser: _inArray(
value: "administrator",
array: $__roleNames
)
@export(as: "isAdminUser")
}
}Условное выполнение операций
Когда включено Выполнение нескольких queries, директивы @include и @skip также можно применять к операциям. Таким образом, мы можем выполнять или не выполнять операцию в зависимости от значения некоторой динамической переменной.
В приведённом ниже запросе будет выполнена только одна из двух операций:
RetrieveContentForAdminUserвыполняется только когда$isAdminUserравноtrueRetrieveContentForNonAdminUserвыполняется только когда$isAdminUserравноfalse
query RetrieveContentForAdminUser
@depends(on: "ExportConditionalVariables")
@include(if: $isAdminUser)
{
# ...
}
query RetrieveContentForNonAdminUser
@depends(on: "ExportConditionalVariables")
@skip(if: $isAdminUser)
{
# ...
}Предоставим два разных ответа для поля content записи в зависимости от того, является ли пользователь администратором:
- Первая операция использует
contentв качестве псевдонима и динамически вычисляет значение поля, объединяя поляoriginalContentиwpAdminEditURLс помощью_sprintf - Вторая операция получает поле
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
}
}Добавление операции для выполнения
Теперь у нас есть две операции, которые могут быть выполнены, однако при выполнении запроса можно указать только одно ?operationName=....
Поэтому мы добавляем операцию ExecuteAll, которая зависит от RetrieveContentForAdminUser и RetrieveContentForNonAdminUser и содержит простое поле id (поскольку в операции необходимо запрашивать хотя бы что-то):
query ExecuteAll
@depends(on: [
"RetrieveContentForAdminUser",
"RetrieveContentForNonAdminUser"
])
{
id
}Вызов эндпоинта с ?operationName=ExecuteAll теперь загрузит обе операции, однако реально выполнена будет только одна из них.
Удаление ненужных данных
Последний шаг — удалить все вспомогательные поля (вывод которых нам не нужен в ответе) с помощью @remove.
Итоговый GraphQL-запрос выглядит следующим образом:
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
}