Manejar los payloads de mutaciones
Los campos de mutación pueden configurarse para devolver cualquiera de estos 2 tipos de entidades distintos:
- Un tipo de objeto payload
- Directamente la entidad mutada
Tipo de objeto payload
Un tipo de objeto payload contiene todos los datos relativos a la mutación:
- El estado de la mutación (éxito o fallo)
- Los errores (si los hay) usando tipos GraphQL distintivos, o
- La entidad mutada con éxito
Por ejemplo, la mutación updatePost devuelve un objeto de tipo PostUpdateMutationPayload, y todavía tenemos que consultar su campo post para recuperar la entidad post actualizada:
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
}
}
}El objeto payload nos permite representar mejor los errores, incluso teniendo un tipo GraphQL único por cada tipo de error. Esto nos permite presentar diferentes reacciones para diferentes errores en la aplicación, mejorando así la experiencia del usuario.
En el ejemplo de arriba, si la operación tuvo éxito, recibiremos:
{
"data": {
"updatePost": {
"status": "SUCCESS",
"errors": null,
"post": {
"id": 1724,
"title": "Some title",
"status": "publish"
}
}
}
}Si el usuario no ha iniciado sesión, recibiremos:
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "UserIsNotLoggedInErrorPayload",
"message": "You must be logged in to create or update custom posts"
}
],
"post": null
}
}
}Si el usuario no tiene permiso para editar posts, recibiremos:
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "LoggedInUserHasNoEditingCustomPostCapabilityErrorPayload",
"message": "Your user doesn't have permission for editing custom posts."
}
],
"post": null
}
}
}En este modo, el esquema GraphQL contendrá muchos tipos adicionales MutationPayload, MutationErrorPayloadUnion y ErrorPayload, por lo que tendrá un tamaño mayor:

Consultar los objetos payload de mutación
Cada mutación en el esquema tiene un campo correspondiente para consultar sus objetos payload recién creados, con nombre {mutationName}MutationPayloadObjects.
Estos campos incluyen:
addCommentToCustomPostMutationPayloadObjects(paraaddCommentToCustomPost)createCustomPostMutationPayloadObjects(paracreateCustomPost)createMediaItemMutationPayloadObjects(paracreateMediaItem)createPageMutationPayloadObjects(paracreatePage)createPostMutationPayloadObjects(paracreatePost)removeFeaturedImageFromCustomPostMutationPayloadObjects(pararemoveFeaturedImageFromCustomPost)replyCommentMutationPayloadObjects(parareplyComment)setCategoriesOnPostMutationPayloadObjects(parasetCategoriesOnPost)setFeaturedImageOnCustomPostMutationPayloadObjects(parasetFeaturedImageOnCustomPost)setTagsOnPostMutationPayloadObjects(parasetTagsOnPost)updateCustomPostMutationPayloadObjects(paraupdateCustomPost)updatePageMutationPayloadObjects(paraupdatePage)updatePostMutationPayloadObjects(paraupdatePost)
Estos campos nos permiten recuperar los resultados de mutaciones ejecutadas usando @applyField mientras iteramos los elementos de un array.
Por ejemplo, la siguiente consulta duplica posts en bloque:
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
}
}
}Por defecto, estos campos no se añaden al esquema GraphQL. Para ello, debemos seleccionar la opción "Use payload types for mutations, and add fields to query those payload objects".
Entidad mutada
La mutación devolverá directamente la entidad mutada en caso de éxito, o null en caso de fallo, y cualquier mensaje de error se mostrará en la entrada de nivel superior errors de la respuesta JSON.
Por ejemplo, la mutación updatePost devolverá el objeto de tipo Post:
mutation UpdatePost {
updatePost(input: {
id: 1724,
title: "New title",
status: publish
}) {
id
title
status
}
}Si la operación tuvo éxito, recibiremos:
{
"data": {
"updatePost": {
"id": 1724,
"title": "Some title",
"status": "publish"
}
}
}En caso de errores, estos aparecerán bajo la entrada errors de la respuesta. Por ejemplo, si el usuario no ha iniciado sesión, recibiremos:
{
"errors": [
{
"message": "You must be logged in to create or update custom posts'",
"locations": [
{
"line": 2,
"column": 3
}
]
}
],
"data": {
"updatePost": null
}
}Debemos tener en cuenta que, como resultado, la entrada de nivel superior errors contendrá no solo errores de sintaxis, validación del esquema y lógica (p. ej.: no pasar el nombre del argumento de un campo, solicitar un campo inexistente, o llamar a _sendHTTPRequest cuando la red está caída respectivamente), sino también errores de "validación de contenido" (p. ej.: "no estás autorizado a modificar este post").
Como no se añaden tipos adicionales, el esquema GraphQL será más esbelto:

Manejar el tipo de objeto payload para mutaciones
Veamos cómo manejar la primera opción, el tipo de objeto payload.
Las mutaciones en el esquema devuelven algún objeto payload, que proporciona cualquier error resultante de la mutación, o el objeto modificado si tuvo éxito (estas 2 propiedades probablemente son exclusivas: o bien errors o object tendrá un valor, y la otra será null).
Los errores se proporcionan mediante algún tipo "ErrorPayloadUnion", que contiene todos los errores posibles para esa mutación. Cada posible error es algún tipo "ErrorPayload" que implementa la interfaz ErrorPayload.
Por ejemplo, la operación updatePost devuelve un PostUpdateMutationPayload, que contiene los siguientes campos:
status: si la operación tuvo éxito o no, con el valorSUCCESSoFAILUREpostypostID: el objeto post actualizado y su ID, si la actualización tuvo éxitoerrors: una lista deCustomPostUpdateMutationErrorPayloadUnion, si la actualización falló.
El tipo unión CustomPostUpdateMutationErrorPayloadUnion contiene la lista de todos los posibles errores que pueden producirse al modificar un custom post:
CustomPostDoesNotExistErrorPayloadGenericErrorPayloadLoggedInUserHasNoEditingCustomPostCapabilityErrorPayloadLoggedInUserHasNoPermissionToEditCustomPostErrorPayloadLoggedInUserHasNoPublishingCustomPostCapabilityErrorPayloadUserIsNotLoggedInErrorPayload
El tipo de error GenericErrorPayload está contenido por todos los tipos "ErrorPayloadUnion". Se usa siempre que no se pueda señalar la razón específica del error, como cuando wp_update_post simplemente produce WP_Error. Este tipo proporciona dos campos adicionales: code y data.
Entonces, para ejecutar la mutación updatePost, podemos ejecutar:
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 la operación tuvo éxito, recibiremos:
{
"data": {
"updatePost": {
"status": "SUCCESS",
"errors": null,
"post": {
"id": 1724,
"title": "This incredible title"
}
}
}
}Si el usuario no ha iniciado sesión, recibiremos:
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "UserIsNotLoggedInErrorPayload",
"message": "You must be logged in to create or update custom posts"
}
],
"post": null
}
}
}Si el usuario no tiene permiso para editar posts, recibiremos:
{
"data": {
"updatePost": {
"status": "FAILURE",
"errors": [
{
"__typename": "LoggedInUserHasNoEditingCustomPostCapabilityErrorPayload",
"message": "Your user doesn't have permission for editing custom posts."
}
],
"post": null
}
}
}