Zarządzanie payloadami mutations
Pola mutation można skonfigurować tak, aby zwracały jeden z 2 różnych typów encji:
- Typ obiektu payload
- Bezpośrednio zmodyfikowaną encję
Typ obiektu payload
Typ obiektu payload zawiera wszystkie dane dotyczące mutation:
- Status mutation (sukces lub niepowodzenie)
- Błędy (jeśli istnieją) przy użyciu odrębnych typów GraphQL, lub
- Pomyślnie zmodyfikowaną encję
Na przykład mutation updatePost zwraca obiekt typu PostUpdateMutationPayload, a my nadal musimy odpytać jego pole post, aby pobrać zaktualizowaną encję 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
}
}
}Obiekt payload pozwala nam lepiej reprezentować błędy, a nawet posiadać unikalny typ GraphQL dla każdego rodzaju błędu. Dzięki temu możemy prezentować różne reakcje na różne błędy w aplikacji, poprawiając tym samym doświadczenie użytkownika.
W powyższym przykładzie, jeśli operacja zakończyła się sukcesem, otrzymamy:
{
"data": {
"updatePost": {
"status": "SUCCESS",
"errors": null,
"post": {
"id": 1724,
"title": "Some title",
"status": "publish"
}
}
}
}Jeśli użytkownik nie jest zalogowany, otrzymamy:
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "UserIsNotLoggedInErrorPayload",
"message": "You must be logged in to create or update custom posts"
}
],
"post": null
}
}
}Jeśli użytkownik nie ma uprawnień do edycji postów, otrzymamy:
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "LoggedInUserHasNoEditingCustomPostCapabilityErrorPayload",
"message": "Your user doesn't have permission for editing custom posts."
}
],
"post": null
}
}
}W tym trybie schemat GraphQL będzie zawierał wiele dodatkowych typów MutationPayload, MutationErrorPayloadUnion i ErrorPayload, więc będzie miał większy rozmiar:

Odpytywanie obiektów payload mutations
Każda mutation w schemacie posiada odpowiednie pole do odpytywania jej niedawno utworzonych obiektów payload, o nazwie {mutationName}MutationPayloadObjects.
Te pola obejmują:
addCommentToCustomPostMutationPayloadObjects(dlaaddCommentToCustomPost)createCustomPostMutationPayloadObjects(dlacreateCustomPost)createMediaItemMutationPayloadObjects(dlacreateMediaItem)createPageMutationPayloadObjects(dlacreatePage)createPostMutationPayloadObjects(dlacreatePost)removeFeaturedImageFromCustomPostMutationPayloadObjects(dlaremoveFeaturedImageFromCustomPost)replyCommentMutationPayloadObjects(dlareplyComment)setCategoriesOnPostMutationPayloadObjects(dlasetCategoriesOnPost)setFeaturedImageOnCustomPostMutationPayloadObjects(dlasetFeaturedImageOnCustomPost)setTagsOnPostMutationPayloadObjects(dlasetTagsOnPost)updateCustomPostMutationPayloadObjects(dlaupdateCustomPost)updatePageMutationPayloadObjects(dlaupdatePage)updatePostMutationPayloadObjects(dlaupdatePost)
Te pola umożliwiają nam pobieranie wyników mutations wykonanych przy użyciu @applyField podczas iterowania po elementach tablicy.
Na przykład poniższe zapytanie duplikuje posty zbiorczo:
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
}
}
}Domyślnie te pola nie są dodawane do schematu GraphQL. W tym celu musimy wybrać opcję "Use payload types for mutations, and add fields to query those payload objects".
Zmodyfikowana encja
Mutation zwróci bezpośrednio zmodyfikowaną encję w przypadku sukcesu, lub null w przypadku niepowodzenia, a wszelkie komunikaty o błędach będą wyświetlane we wpisie errors najwyższego poziomu odpowiedzi JSON.
Na przykład mutation updatePost zwróci obiekt typu Post:
mutation UpdatePost {
updatePost(input: {
id: 1724,
title: "New title",
status: publish
}) {
id
title
status
}
}Jeśli operacja zakończyła się sukcesem, otrzymamy:
{
"data": {
"updatePost": {
"id": 1724,
"title": "Some title",
"status": "publish"
}
}
}W przypadku błędów pojawią się one we wpisie errors odpowiedzi. Na przykład, jeśli użytkownik nie jest zalogowany, otrzymamy:
{
"errors": [
{
"message": "You must be logged in to create or update custom posts'",
"locations": [
{
"line": 2,
"column": 3
}
]
}
],
"data": {
"updatePost": null
}
}Musimy zauważyć, że w rezultacie wpis errors najwyższego poziomu będzie zawierał nie tylko błędy składni, walidacji schematu i logiki (np.: nieprzekazanie nazwy argumentu pola, żądanie nieistniejącego pola, lub wywołanie _sendHTTPRequest przy braku połączenia sieciowego), ale także błędy "walidacji treści" (np.: "nie masz uprawnień do modyfikowania tego posta").
Ponieważ nie są dodawane żadne dodatkowe typy, schemat GraphQL będzie wyglądał bardziej przejrzyście:

Zarządzanie typem obiektu payload dla mutations
Zobaczmy, jak obsługiwać pierwszą opcję, typ obiektu payload.
Mutations w schemacie zwracają pewien obiekt payload, który dostarcza wszelkich błędów wynikających z mutation, lub zmodyfikowany obiekt w przypadku sukcesu (te 2 właściwości są najprawdopodobniej wzajemnie wykluczające: albo errors, albo object będzie miało wartość, a drugie będzie null).
Błędy są dostarczane za pośrednictwem pewnego typu "ErrorPayloadUnion", zawierającego wszystkie możliwe błędy dla danej mutation. Każdy możliwy błąd jest pewnym typem "ErrorPayload", który implementuje interfejs ErrorPayload.
Na przykład operacja updatePost zwraca PostUpdateMutationPayload, który zawiera następujące pola:
status: czy operacja zakończyła się sukcesem, czy nie, z wartościąSUCCESSlubFAILUREpostipostID: zaktualizowany obiekt post i jego ID, jeśli aktualizacja zakończyła się sukcesemerrors: listaCustomPostUpdateMutationErrorPayloadUnion, jeśli aktualizacja się nie powiodła.
Typ union CustomPostUpdateMutationErrorPayloadUnion zawiera listę wszystkich możliwych błędów, które mogą wystąpić podczas modyfikowania custom post:
CustomPostDoesNotExistErrorPayloadGenericErrorPayloadLoggedInUserHasNoEditingCustomPostCapabilityErrorPayloadLoggedInUserHasNoPermissionToEditCustomPostErrorPayloadLoggedInUserHasNoPublishingCustomPostCapabilityErrorPayloadUserIsNotLoggedInErrorPayload
Typ błędu GenericErrorPayload jest zawarty we wszystkich typach "ErrorPayloadUnion". Jest używany zawsze, gdy nie można wskazać konkretnej przyczyny błędu, na przykład gdy wp_update_post po prostu zwraca WP_Error. Ten typ udostępnia dwa dodatkowe pola: code i data.
Następnie, aby wykonać mutation updatePost, możemy wykonać:
mutation UpdatePost(
$postId: ID!
$title: String!
) {
updatePost(
input: {
id: $postId,
title: $title,
}
) {
status
errors {
__typename
...on ErrorPayload {
message
}
...on GenericErrorPayload {
code
}
}
post {
id
title
}
}
}Jeśli operacja zakończyła się sukcesem, otrzymamy:
{
"data": {
"updatePost": {
"status": "SUCCESS",
"errors": null,
"post": {
"id": 1724,
"title": "This incredible title"
}
}
}
}Jeśli użytkownik nie jest zalogowany, otrzymamy:
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "UserIsNotLoggedInErrorPayload",
"message": "You must be logged in to create or update custom posts"
}
],
"post": null
}
}
}Jeśli użytkownik nie ma uprawnień do edycji postów, otrzymamy:
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "LoggedInUserHasNoEditingCustomPostCapabilityErrorPayload",
"message": "Your user doesn't have permission for editing custom posts."
}
],
"post": null
}
}
}