Gérer les payloads de mutations
Les champs de mutation peuvent être configurés pour retourner l'un de ces 2 types d'entités distincts :
- Un type d'objet payload
- Directement l'entité mutée
Type d'objet payload
Un type d'objet payload contient toutes les données relatives à la mutation :
- Le statut de la mutation (succès ou échec)
- Les erreurs (le cas échéant) en utilisant des types GraphQL distinctifs, ou
- L'entité mutée avec succès
Par exemple, la mutation updatePost retourne un objet de type PostUpdateMutationPayload, et nous devons encore interroger son champ post pour récupérer l'entité article mise à jour :
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
}
}
}L'objet payload nous permet de mieux représenter les erreurs, en disposant même d'un type GraphQL unique par type d'erreur. Cela nous permet de présenter des réactions différentes pour différentes erreurs dans l'application, améliorant ainsi l'expérience utilisateur.
Dans l'exemple ci-dessus, si l'opération a réussi, nous recevrons :
{
"data": {
"updatePost": {
"status": "SUCCESS",
"errors": null,
"post": {
"id": 1724,
"title": "Some title",
"status": "publish"
}
}
}
}Si l'utilisateur n'est pas connecté, nous recevrons :
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "UserIsNotLoggedInErrorPayload",
"message": "You must be logged in to create or update custom posts"
}
],
"post": null
}
}
}Si l'utilisateur n'a pas la permission de modifier des articles, nous recevrons :
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "LoggedInUserHasNoEditingCustomPostCapabilityErrorPayload",
"message": "Your user doesn't have permission for editing custom posts."
}
],
"post": null
}
}
}Dans ce mode, le schéma GraphQL contiendra de nombreux types supplémentaires MutationPayload, MutationErrorPayloadUnion et ErrorPayload, ce qui lui donnera une taille plus importante :

Interroger les objets payload de mutation
Chaque mutation dans le schéma dispose d'un champ correspondant pour interroger ses objets payload récemment créés, avec le nom {mutationName}MutationPayloadObjects.
Ces champs comprennent :
addCommentToCustomPostMutationPayloadObjects(pouraddCommentToCustomPost)createCustomPostMutationPayloadObjects(pourcreateCustomPost)createMediaItemMutationPayloadObjects(pourcreateMediaItem)createPageMutationPayloadObjects(pourcreatePage)createPostMutationPayloadObjects(pourcreatePost)removeFeaturedImageFromCustomPostMutationPayloadObjects(pourremoveFeaturedImageFromCustomPost)replyCommentMutationPayloadObjects(pourreplyComment)setCategoriesOnPostMutationPayloadObjects(poursetCategoriesOnPost)setFeaturedImageOnCustomPostMutationPayloadObjects(poursetFeaturedImageOnCustomPost)setTagsOnPostMutationPayloadObjects(poursetTagsOnPost)updateCustomPostMutationPayloadObjects(pourupdateCustomPost)updatePageMutationPayloadObjects(pourupdatePage)updatePostMutationPayloadObjects(pourupdatePost)
Ces champs nous permettent de récupérer les résultats de mutations exécutées avec @applyField lors de l'itération sur les éléments d'un tableau.
Par exemple, la requête suivante duplique des articles en masse :
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
}
}
}Par défaut, ces champs ne sont pas ajoutés au schéma GraphQL. Pour cela, nous devons sélectionner l'option "Use payload types for mutations, and add fields to query those payload objects".
Entité mutée
La mutation retournera directement l'entité mutée en cas de succès, ou null en cas d'échec, et tout message d'erreur sera affiché dans l'entrée de niveau supérieur errors de la réponse JSON.
Par exemple, la mutation updatePost retournera l'objet de type Post :
mutation UpdatePost {
updatePost(input: {
id: 1724,
title: "New title",
status: publish
}) {
id
title
status
}
}Si l'opération a réussi, nous recevrons :
{
"data": {
"updatePost": {
"id": 1724,
"title": "Some title",
"status": "publish"
}
}
}En cas d'erreurs, celles-ci apparaîtront sous l'entrée errors de la réponse. Par exemple, si l'utilisateur n'est pas connecté, nous recevrons :
{
"errors": [
{
"message": "You must be logged in to create or update custom posts'",
"locations": [
{
"line": 2,
"column": 3
}
]
}
],
"data": {
"updatePost": null
}
}Nous devons noter que, par conséquent, l'entrée de niveau supérieur errors contiendra non seulement des erreurs de syntaxe, de validation du schéma et de logique (ex. : ne pas passer le nom d'un argument de champ, demander un champ inexistant, ou appeler _sendHTTPRequest alors que le réseau est hors ligne respectivement), mais aussi des erreurs de « validation de contenu » (ex. : « vous n'êtes pas autorisé à modifier cet article »).
Comme aucun type supplémentaire n'est ajouté, le schéma GraphQL sera plus épuré :

Gérer le type d'objet payload pour les mutations
Voyons comment gérer la première option, le type d'objet payload.
Les mutations dans le schéma retournent un objet payload, qui fournit toute erreur résultant de la mutation, ou l'objet modifié en cas de succès (ces 2 propriétés sont très probablement exclusives : soit errors soit object aura une valeur, et l'autre sera null).
Les erreurs sont fournies via un type « ErrorPayloadUnion », contenant toutes les erreurs possibles pour cette mutation. Chaque erreur possible est un type « ErrorPayload » qui implémente l'interface ErrorPayload.
Par exemple, l'opération updatePost retourne un PostUpdateMutationPayload, qui contient les champs suivants :
status: si l'opération a réussi ou non, avec la valeurSUCCESSouFAILUREpostetpostID: l'objet article mis à jour et son identifiant, si la mise à jour a réussierrors: une liste deCustomPostUpdateMutationErrorPayloadUnion, si la mise à jour a échoué.
Le type union CustomPostUpdateMutationErrorPayloadUnion contient la liste de toutes les erreurs possibles pouvant survenir lors de la modification d'un custom post :
CustomPostDoesNotExistErrorPayloadGenericErrorPayloadLoggedInUserHasNoEditingCustomPostCapabilityErrorPayloadLoggedInUserHasNoPermissionToEditCustomPostErrorPayloadLoggedInUserHasNoPublishingCustomPostCapabilityErrorPayloadUserIsNotLoggedInErrorPayload
Le type d'erreur GenericErrorPayload est contenu par tous les types « ErrorPayloadUnion ». Il est utilisé lorsque la raison spécifique de l'erreur ne peut pas être identifiée, comme lorsque wp_update_post produit simplement WP_Error. Ce type fournit deux champs supplémentaires : code et data.
Ainsi, pour exécuter la mutation updatePost, nous pouvons exécuter :
mutation UpdatePost(
$postId: ID!
$title: String!
) {
updatePost(
input: {
id: $postId,
title: $title,
}
) {
status
errors {
__typename
...on ErrorPayload {
message
}
...on GenericErrorPayload {
code
}
}
post {
id
title
}
}
}Si l'opération a réussi, nous recevrons :
{
"data": {
"updatePost": {
"status": "SUCCESS",
"errors": null,
"post": {
"id": 1724,
"title": "This incredible title"
}
}
}
}Si l'utilisateur n'est pas connecté, nous recevrons :
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "UserIsNotLoggedInErrorPayload",
"message": "You must be logged in to create or update custom posts"
}
],
"post": null
}
}
}Si l'utilisateur n'a pas la permission de modifier des articles, nous recevrons :
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "LoggedInUserHasNoEditingCustomPostCapabilityErrorPayload",
"message": "Your user doesn't have permission for editing custom posts."
}
],
"post": null
}
}
}