Обработка payload-объектов мутаций
Поля мутаций можно настроить для возврата одного из 2 различных типов сущностей:
- Тип payload-объекта
- Непосредственно изменённая сущность
Тип payload-объекта
Тип payload-объекта содержит все данные, связанные с мутацией:
- Статус мутации (успех или ошибка)
- Ошибки (если есть) с использованием отличительных типов GraphQL, или
- Успешно изменённая сущность
Например, мутация updatePost возвращает объект типа PostUpdateMutationPayload, и нам всё равно нужно запросить его поле post, чтобы получить обновлённую сущность поста:
mutation UpdatePost {
updatePost(input: {
id: 1724,
title: "New title",
status: publish
}) {
# This is the status of the mutation: SUCCESS or FAILURE
status
errors {
__typename
...on ErrorPayload {
message
}
}
post {
id
title
# This is the status of the post: publish, pending, trash, etc
status
}
}
}Payload-объект позволяет нам лучше представлять ошибки, даже имея уникальный тип GraphQL для каждого вида ошибки. Это позволяет нам реализовывать различные реакции на разные ошибки в приложении, тем самым улучшая пользовательский опыт.
В приведённом выше примере, если операция прошла успешно, мы получим:
{
"data": {
"updatePost": {
"status": "SUCCESS",
"errors": null,
"post": {
"id": 1724,
"title": "Some title",
"status": "publish"
}
}
}
}Если пользователь не вошёл в систему, мы получим:
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "UserIsNotLoggedInErrorPayload",
"message": "You must be logged in to create or update custom posts"
}
],
"post": null
}
}
}Если у пользователя нет разрешения на редактирование постов, мы получим:
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "LoggedInUserHasNoEditingCustomPostCapabilityErrorPayload",
"message": "Your user doesn't have permission for editing custom posts."
}
],
"post": null
}
}
}В этом режиме схема GraphQL будет содержать множество дополнительных типов MutationPayload, MutationErrorPayloadUnion и ErrorPayload, поэтому её размер будет больше:

Запрос payload-объектов мутации
Каждая мутация в схеме имеет соответствующее поле для запроса недавно созданных payload-объектов с именем {mutationName}MutationPayloadObjects.
Эти поля включают:
addCommentToCustomPostMutationPayloadObjects(дляaddCommentToCustomPost)createCustomPostMutationPayloadObjects(дляcreateCustomPost)createMediaItemMutationPayloadObjects(дляcreateMediaItem)createPageMutationPayloadObjects(дляcreatePage)createPostMutationPayloadObjects(дляcreatePost)removeFeaturedImageFromCustomPostMutationPayloadObjects(дляremoveFeaturedImageFromCustomPost)replyCommentMutationPayloadObjects(дляreplyComment)setCategoriesOnPostMutationPayloadObjects(дляsetCategoriesOnPost)setFeaturedImageOnCustomPostMutationPayloadObjects(дляsetFeaturedImageOnCustomPost)setTagsOnPostMutationPayloadObjects(дляsetTagsOnPost)updateCustomPostMutationPayloadObjects(дляupdateCustomPost)updatePageMutationPayloadObjects(дляupdatePage)updatePostMutationPayloadObjects(дляupdatePost)
Эти поля позволяют нам получать результаты мутаций, выполненных с помощью @applyField при итерации элементов массива.
Например, следующий запрос дублирует посты пакетно:
query GetPostsAndExportData
{
postsToDuplicate: posts {
title
rawContent
excerpt
# Already create (and export) the inputs for the mutation
postInput: _echo(value: {
title: $__title
contentAs: {
html: $__rawContent
},
excerpt: $__excerpt
})
@export(as: "postInput", type: LIST)
@remove
}
}
mutation CreatePosts
@depends(on: "GetPostsAndExportData")
{
createdPostMutationPayloadObjectIDs: _echo(value: $postInput)
@underEachArrayItem(
passValueOnwardsAs: "input"
)
@applyField(
name: "createPost"
arguments: {
input: $input
},
setResultInResponse: true
)
@export(as: "createdPostMutationPayloadObjectIDs")
}
query DuplicatePosts
@depends(on: "CreatePosts")
{
createdPostMutationObjectPayloads: createPostMutationPayloadObjects(input: {
ids: $createdPostMutationPayloadObjectIDs
}) {
status
errors {
__typename
...on ErrorPayload {
message
}
}
post {
id
title
rawContent
excerpt
}
}
}По умолчанию эти поля не добавляются в схему GraphQL. Для этого необходимо выбрать опцию «Use payload types for mutations, and add fields to query those payload objects».
Изменённая сущность
Мутация напрямую вернёт изменённую сущность в случае успеха или null в случае ошибки, а любые сообщения об ошибках будут отображены в записи верхнего уровня errors ответа JSON.
Например, мутация updatePost вернёт объект типа Post:
mutation UpdatePost {
updatePost(input: {
id: 1724,
title: "New title",
status: publish
}) {
id
title
status
}
}Если операция прошла успешно, мы получим:
{
"data": {
"updatePost": {
"id": 1724,
"title": "Some title",
"status": "publish"
}
}
}В случае ошибок они появятся в записи errors ответа. Например, если пользователь не вошёл в систему, мы получим:
{
"errors": [
{
"message": "You must be logged in to create or update custom posts'",
"locations": [
{
"line": 2,
"column": 3
}
]
}
],
"data": {
"updatePost": null
}
}Необходимо учитывать, что в результате запись верхнего уровня errors будет содержать не только синтаксические ошибки, ошибки валидации схемы и логические ошибки (например: не передано имя аргумента поля, запрошено несуществующее поле или вызов _sendHTTPRequest при недоступной сети соответственно), но и ошибки «валидации содержимого» (например: «у вас нет прав на изменение этого поста»).
Поскольку дополнительные типы не добавляются, схема GraphQL будет выглядеть более компактной:

Обработка типа payload-объекта для мутаций
Рассмотрим, как обрабатывать первый вариант — тип payload-объекта.
Мутации в схеме возвращают некоторый payload-объект, который предоставляет любые ошибки, возникшие в результате мутации, или изменённый объект в случае успеха (эти 2 свойства, скорее всего, являются взаимоисключающими: либо errors, либо object будет иметь значение, а другое будет null).
Ошибки предоставляются через некоторый тип «ErrorPayloadUnion», содержащий все возможные ошибки для данной мутации. Каждая возможная ошибка является некоторым типом «ErrorPayload», реализующим интерфейс ErrorPayload.
Например, операция updatePost возвращает PostUpdateMutationPayload, который содержит следующие поля:
status: успешно ли выполнена операция или нет, со значениемSUCCESSилиFAILUREpostиpostID: обновлённый объект поста и его ID, если обновление прошло успешноerrors: списокCustomPostUpdateMutationErrorPayloadUnion, если обновление не удалось.
Тип объединения CustomPostUpdateMutationErrorPayloadUnion содержит список всех возможных ошибок, которые могут возникнуть при изменении custom post:
CustomPostDoesNotExistErrorPayloadGenericErrorPayloadLoggedInUserHasNoEditingCustomPostCapabilityErrorPayloadLoggedInUserHasNoPermissionToEditCustomPostErrorPayloadLoggedInUserHasNoPublishingCustomPostCapabilityErrorPayloadUserIsNotLoggedInErrorPayload
Тип ошибки GenericErrorPayload содержится во всех типах «ErrorPayloadUnion». Он используется всякий раз, когда невозможно указать конкретную причину ошибки, например когда wp_update_post просто возвращает WP_Error. Этот тип предоставляет два дополнительных поля: code и data.
Итак, для выполнения мутации updatePost можно выполнить:
mutation UpdatePost(
$postId: ID!
$title: String!
) {
updatePost(
input: {
id: $postId,
title: $title,
}
) {
status
errors {
__typename
...on ErrorPayload {
message
}
...on GenericErrorPayload {
code
}
}
post {
id
title
}
}
}Если операция прошла успешно, мы получим:
{
"data": {
"updatePost": {
"status": "SUCCESS",
"errors": null,
"post": {
"id": 1724,
"title": "This incredible title"
}
}
}
}Если пользователь не вошёл в систему, мы получим:
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "UserIsNotLoggedInErrorPayload",
"message": "You must be logged in to create or update custom posts"
}
],
"post": null
}
}
}Если у пользователя нет разрешения на редактирование постов, мы получим:
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "LoggedInUserHasNoEditingCustomPostCapabilityErrorPayload",
"message": "Your user doesn't have permission for editing custom posts."
}
],
"post": null
}
}
}