Returning different types on mutations

Mutation fields can be configured to return either of these 2 different entity types:

  • A payload object type
  • Directly the mutated entity

Payload object type permalink

A payload object type contains all the data concerning the mutation:

  • The status of the mutation (success or failure)
  • The errors (if any) using distinctive GraphQL types, or
  • The successfully mutated entity

For instance, mutation updatePost returns an object of type PostUpdateMutationPayload, and we still need to query its field post to retrieve the updated post entity:

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

The payload object allows us to represent better the errors, even having a unique GraphQL type per kind of error. This allows us to present different reactions for different errors in the application, thus improving the user experience.

In the example above, if the operation was successful, we will receive:

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

If the user is not logged in, we will receive:

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

If the user doesn't have the permission to edit posts, we will receive:

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

In this mode, the GraphQL schema will contain plenty of additional MutationPayload, MutationErrorPayloadUnion and ErrorPayload types, so it will have a bigger size:

GraphQL schema with payload object types for mutations
GraphQL schema with payload object types for mutations

Mutated entity permalink

The mutation will directly return the mutated entity in case of success, or null in case of failure, and any error message will be displayed in the JSON response's top-level errors entry.

For instance, mutation updatePost will return the object of type Post:

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

If the operation was successful, we will receive:

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

In case of errors, these will appear under the errors entry of the response. For instance, if the user is not logged in, we will receive:

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

We must notice that, as a result, the top-level errors entry will contain not only syntax, schema validation and logic errors (eg: not passing a field argument's name, requesting a non-existing field, or calling _sendHTTPRequest and the network is down respectively), but also "content validation" errors (eg: "you're not authorized to modify this post").

Because there are no additional types added, the GraphQL schema will look leaner:

GraphQL schema without payload object types for mutations
GraphQL schema without payload object types for mutations