Extensions Reference
Extensions ReferenceResponse Error Trigger

Response Error Trigger

Explicitly add an error entry to the response to trigger the failure of the GraphQL request (whenever a field does not meet the expected conditions).

Description

This module adds global field _fail and directive @fail to the GraphQL schema, which add an entry to the errors property in the response.

Field _fail adds the error always, and directive @fail whenever the condition under argument condition is met (either if the field value is null, or empty; by default, it is IS_NULL):

query {
  _fail(message: "Some error")
  
  posts {
    featuredImage @fail(
      # condition: IS_NULL, \<= This is the default value
      message: "The post does not have a featured image"
    ) {
      id
      src
    }
  }
  
  users {
    name @fail(
      condition: IS_EMPTY,
      message: "The retrieved user does not have a name"
    )
  }
}

Both of them can also receive argument data, to provide contextual information in the error response.

These schema elements are useful to explicitly indicate that there is an error in the executed GraphQL query, whenever such an error does not happen on natural circumstances.

Then, in our application on the client side (such as JavaScript with a headless setup), we can check if entry errors exists and, based on that, either process the GraphQL response or show an error message to the user:

/**
 * If the response contains error(s), return a concatenated error message
 *
 * @param {Object} response A response object from the GraphQL server
 * @return {string|null} The error message or nothing
 */
const maybeGetErrorMessage = (response) => {
  if (response.errors && response.errors.length) {
    return sprintf(
      __(`The API produced the following error(s): "%s"`, 'gato-graphql'),
      response.errors.map(error => error.message).join( __('", "') )
    );
  }
  return null;
}
 
const maybeErrorMessage = maybeGetErrorMessage(response);
if (maybeErrorMessage) {
  // Show error to the user
  // ...
} else {
  // Process response
  // ...
}

Examples

Retrieving a post with a non-existent ID will naturally return null. If we need to treat this condition as an error, we can use directive @fail:

query GetPost($id: ID!) {
  post(by:{id: $id})
    @fail(
      message: "There is no post with the provided ID"
      data: {
        id: $id
      }
    )
  {
    id
    title
  }
}

In combination with the Multiple Query Execution extension, we can obtain the same results using _fail (notice that operation FailIfPostNotExists is not executed whenever $postExists is true):

query GetPost($id: ID!) {
  post(by:{id: $id}) {
    id
    title
  }
  _notNull(value: $__post) @export(as: "postExists")
}
 
query FailIfPostNotExists($id: ID!)
  @skip(if: $postExists)
  @depends(on: "GetPost")
{
  errorMessage: _sprintf(
    string: "There is no post with ID '%s'",
    values: [$id]
  ) @remove
  _fail(
    message: $__errorMessage
    data: {
      id: $id
    }
  ) @remove
}

We can use _fail to ensure that the user with given email does not yet exist:

query EnsureUserDoesNotExist($userEmail: Email!) {
  user( by: { email: $userEmail } ) {
    _fail(
      message: "User with given email already exists"
      data: {
        email: $userEmail
      }
    )
  }
}
 
mutation CreateUser($userData: JSONObject!)
  @depends(on: "EnsureUserDoesNotExist")
{
  # ...
}

We can also use _fail to check if retrieving data from an external API produced errors:

query ConnectToExternalGraphQLAPI($endpoint: String!, $query: String!) {
  externalData: _sendGraphQLHTTPRequest(
    input: {
      endpoint: $endpoint
      query: $query
    }
  ) @export(as: "externalData")
  _propertyIsSetInJSONObject(
    object: $__externalData
    by: {
      key: "errors"
    }
  ) @export(as: "endpointHasErrors")
}
 
query FailIfExternalAPIHasErrors($endpoint: String!)
  @include(if: $endpointHasErrors)
  @depends(on: "ConnectToExternalGraphQLAPI")
{
  errorMessage: _sprintf(
    string: "Connecting to endpoint %s produced errors",
    values: [$endpoint]
  ) @remove
  data: _objectProperty(
    object: $externalData,
    by: {
      key: "errors"
    }
  ) @remove
  _fail(
    message: $__errorMessage
    data: {
      endpoint: $endpoint
      endpointData: $__data
    }
  ) @remove
}
 
query GetExternalAPIData
  @skip(if: $endpointHasErrors)
  @depends(on: "ConnectToExternalGraphQLAPI")
{
  data: _objectProperty(
    object: $externalData,
    by: {
      key: "data"
    }
  )
}