Interagire con l'API GraphQL
Interagire con l'API GraphQLGestire i payload delle mutation

Gestire i payload delle mutation

I campi mutation possono essere configurati per restituire uno di questi 2 tipi di entità distinti:

  • Un tipo di oggetto payload
  • Direttamente l'entità modificata

Tipo di oggetto payload

Un tipo di oggetto payload contiene tutti i dati relativi alla mutation:

  • Lo stato della mutation (successo o fallimento)
  • Gli errori (se presenti) utilizzando tipi GraphQL distintivi, oppure
  • L'entità modificata con successo

Ad esempio, la mutation updatePost restituisce un oggetto di tipo PostUpdateMutationPayload, e dobbiamo comunque interrogare il suo campo post per recuperare l'entità post aggiornata:

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'oggetto payload ci consente di rappresentare meglio gli errori, disponendo persino di un tipo GraphQL unico per ogni tipo di errore. Questo ci permette di presentare reazioni diverse per errori diversi nell'applicazione, migliorando così l'esperienza utente.

Nell'esempio sopra, se l'operazione ha avuto successo, riceveremo:

{
  "data": {
    "updatePost": {
      "status": "SUCCESS",
      "errors": null,
      "post": {
        "id": 1724,
        "title": "Some title",
        "status": "publish"
      }
    }
  }
}

Se l'utente non è autenticato, riceveremo:

{
  "data": {
    "updatePost": {
      "status": "FAILURE",
      "errors": [
        {
          "__typename": "UserIsNotLoggedInErrorPayload",
          "message": "You must be logged in to create or update custom posts"
        }
      ],
      "post": null
    }
  }
}

Se l'utente non ha il permesso di modificare i post, riceveremo:

{
  "data": {
    "updatePost": {
      "status": "FAILURE",
      "errors": [
        {
          "__typename": "LoggedInUserHasNoEditingCustomPostCapabilityErrorPayload",
          "message": "Your user doesn't have permission for editing custom posts."
        }
      ],
      "post": null
    }
  }
}

In questa modalità, lo schema GraphQL conterrà numerosi tipi aggiuntivi MutationPayload, MutationErrorPayloadUnion ed ErrorPayload, quindi avrà una dimensione maggiore:

Schema GraphQL con tipi di oggetto payload per le mutation

Interrogare gli oggetti payload delle mutation

Ogni mutation nello schema dispone di un campo corrispondente per interrogare i suoi oggetti payload creati di recente, con il nome {mutationName}MutationPayloadObjects.

Questi campi comprendono:

  • addCommentToCustomPostMutationPayloadObjects (per addCommentToCustomPost)
  • createCustomPostMutationPayloadObjects (per createCustomPost)
  • createMediaItemMutationPayloadObjects (per createMediaItem)
  • createPageMutationPayloadObjects (per createPage)
  • createPostMutationPayloadObjects (per createPost)
  • removeFeaturedImageFromCustomPostMutationPayloadObjects (per removeFeaturedImageFromCustomPost)
  • replyCommentMutationPayloadObjects (per replyComment)
  • setCategoriesOnPostMutationPayloadObjects (per setCategoriesOnPost)
  • setFeaturedImageOnCustomPostMutationPayloadObjects (per setFeaturedImageOnCustomPost)
  • setTagsOnPostMutationPayloadObjects (per setTagsOnPost)
  • updateCustomPostMutationPayloadObjects (per updateCustomPost)
  • updatePageMutationPayloadObjects (per updatePage)
  • updatePostMutationPayloadObjects (per updatePost)

Questi campi ci consentono di recuperare i risultati delle mutation eseguite con @applyField durante l'iterazione sugli elementi di un array.

Ad esempio, la seguente query duplica i post in blocco:

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
    }
  }
}

Per impostazione predefinita, questi campi non vengono aggiunti allo schema GraphQL. Per farlo, dobbiamo selezionare l'opzione "Use payload types for mutations, and add fields to query those payload objects".

Entità modificata

La mutation restituirà direttamente l'entità modificata in caso di successo, oppure null in caso di fallimento, e qualsiasi messaggio di errore verrà visualizzato nella voce di primo livello errors della risposta JSON.

Ad esempio, la mutation updatePost restituirà l'oggetto di tipo Post:

mutation UpdatePost {
  updatePost(input: {
    id: 1724,
    title: "New title",
    status: publish
  }) {
    id
    title
    status
  }
}

Se l'operazione ha avuto successo, riceveremo:

{
  "data": {
    "updatePost": {
      "id": 1724,
      "title": "Some title",
      "status": "publish"
    }
  }
}

In caso di errori, questi appariranno sotto la voce errors della risposta. Ad esempio, se l'utente non è autenticato, riceveremo:

{
    "errors": [
      {
        "message": "You must be logged in to create or update custom posts'",
        "locations": [
          {
            "line": 2,
            "column": 3
          }
        ]
      }
  ],
  "data": {
    "updatePost": null
  }
}

Dobbiamo notare che, di conseguenza, la voce di primo livello errors conterrà non solo errori di sintassi, di validazione dello schema e di logica (es.: non passare il nome di un argomento di campo, richiedere un campo inesistente, o chiamare _sendHTTPRequest mentre la rete è offline, rispettivamente), ma anche errori di "validazione del contenuto" (es.: "non sei autorizzato a modificare questo post").

Poiché non viene aggiunto alcun tipo aggiuntivo, lo schema GraphQL apparirà più snello:

Schema GraphQL senza tipi di oggetto payload per le mutation

Gestire il tipo di oggetto payload per le mutation

Vediamo come gestire la prima opzione, il tipo di oggetto payload.

Le mutation nello schema restituiscono un oggetto payload, che fornisce qualsiasi errore risultante dalla mutation, oppure l'oggetto modificato in caso di successo (queste 2 proprietà sono molto probabilmente esclusive: o errors o object avrà un valore, e l'altra sarà null).

Gli errori vengono forniti tramite un tipo "ErrorPayloadUnion", contenente tutti i possibili errori per quella mutation. Ogni errore possibile è un tipo "ErrorPayload" che implementa l'interfaccia ErrorPayload.

Ad esempio, l'operazione updatePost restituisce un PostUpdateMutationPayload, che contiene i seguenti campi:

  • status: se l'operazione ha avuto successo o meno, con il valore SUCCESS o FAILURE
  • post e postID: l'oggetto post aggiornato e il suo ID, se l'aggiornamento ha avuto successo
  • errors: un elenco di CustomPostUpdateMutationErrorPayloadUnion, se l'aggiornamento è fallito.

Il tipo union CustomPostUpdateMutationErrorPayloadUnion contiene l'elenco di tutti i possibili errori che possono verificarsi durante la modifica di un custom post:

  • CustomPostDoesNotExistErrorPayload
  • GenericErrorPayload
  • LoggedInUserHasNoEditingCustomPostCapabilityErrorPayload
  • LoggedInUserHasNoPermissionToEditCustomPostErrorPayload
  • LoggedInUserHasNoPublishingCustomPostCapabilityErrorPayload
  • UserIsNotLoggedInErrorPayload

Il tipo di errore GenericErrorPayload è contenuto da tutti i tipi "ErrorPayloadUnion". Viene utilizzato ogni volta che non è possibile individuare la ragione specifica dell'errore, come quando wp_update_post produce semplicemente WP_Error. Questo tipo fornisce due campi aggiuntivi: code e data.

Quindi, per eseguire la mutation updatePost, possiamo eseguire:

mutation UpdatePost(
  $postId: ID!
  $title: String!
) {
  updatePost(
    input: {
      id: $postId,
      title: $title,
    }
  ) {
    status
    errors {
      __typename
      ...on ErrorPayload {
        message
      }
      ...on GenericErrorPayload {
        code
      }
    }
    post {
      id
      title
    }
  }
}

Se l'operazione ha avuto successo, riceveremo:

{
  "data": {
    "updatePost": {
      "status": "SUCCESS",
      "errors": null,
      "post": {
        "id": 1724,
        "title": "This incredible title"
      }
    }
  }
}

Se l'utente non è autenticato, riceveremo:

{
  "data": {
    "updatePost": {
      "status": "FAILURE",
      "errors": [
        {
          "__typename": "UserIsNotLoggedInErrorPayload",
          "message": "You must be logged in to create or update custom posts"
        }
      ],
      "post": null
    }
  }
}

Se l'utente non ha il permesso di modificare i post, riceveremo:

{
  "data": {
    "updatePost": {
      "status": "FAILURE",
      "errors": [
        {
          "__typename": "LoggedInUserHasNoEditingCustomPostCapabilityErrorPayload",
          "message": "Your user doesn't have permission for editing custom posts."
        }
      ],
      "post": null
    }
  }
}