Errors in Mutations
Introduction
In the last lesson, we learned how to use mutations in Relay to update data. In this lesson, we will learn how to handle errors in mutations.
Learning Objectives
By the end of this lesson, you will be able to:
- Handle user and system errors in mutations
 - Understand the difference between user and system errors
 - Know how to use the 
onErrorandonCompletedcallbacks in theuseMutationhook 
Preparation
Continue directly from where we left off in the last lesson or start fresh with the initial setup in the src/Chapter9/Lesson2/Begin folder.
Run npm install in the src/Chapter9/Lesson2/Begin/ folder to install the necessary packages.
Recap
- A lot of things.
 
Mutating data in a system always carries the risk of errors. In GraphQL, we typically encounter two types of errors:
- User Errors: These errors occur when the user provides incorrect input.
 - System Errors: These errors are caused by issues in the system itself, such as database failures or network problems.
 
The key distinction is that user errors are within the user's control, while system errors are not. For example, if the database system is down, the user cannot do anything about it. However, if the user inputs invalid data, you can display an error message and ask them to correct it.
User Errors
In GraphQL mutations, user errors are included in the response.
This means you can directly select these errors in your mutation query.
By using the errors field in the mutation response, you can provide visual feedback to the user when something goes wrong.
    mutation addToBasketButtonMutation($productId: ID!, $quantity: Int!) {
      addToBasket(input: { productId: $productId, quantity: $quantity }) {
        shoppingBasket {
          id
          items {
            id
            ...cartCatalogItemQuantity_shoppingBasketItem
            ...cartItemsCatalogItemTotal_shoppingBasketItem
            ...cartItemsCatalogItemInfo_shoppingBasketItem
          }
        }
        errors {
          ... on QuantityCannotBeNegativeError {
            kind: __typename
          }
        }
      }
    }
The Relay compiler is smart in handling union types.
It generates a type for the errors field that includes all selected error types, using __typename as the discriminator.
Besides the predefined error types, there's also a %other type, which signifies the presence of additional, unspecified error types.
Note that %other is never the actual value you'll receive; it's just a placeholder.
This is important for schema evolution, allowing the server to introduce new error types without breaking existing clients.
Here’s how a typical mutation call might look:
mutate({
  variables: { productId, quantity },
  onCompleted: (res) => {
    if (res.addToBasket.errors && res.addToBasket.errors.length > 0) {
      switch (res.addToBasket.errors[0].kind) {
        case "QuantityCannotBeNegativeError":
          setIsQuantityValid(false);
          break;
        default:
          alert("Oops something went wrong. Please try again.");
          break;
      }
    } else {
      setIsQuantityValid(true);
    }
  },
});
You can replace the response from the server with a mock response to test the %other case.
{
    "data": {
        "addToBasket": {
            "shoppingBasket": null,
            "errors": [
                {
                    "__typename": "ProductOutOfStockError",
                    "kind": "ProductOutOfStockError",
                    "message": "The product is out of stock"
                },
                {
                    "__typename": "QuantityCannotBeNegativeError",
                    "kind": "QuantityCannotBeNegativeError",
                    "message": "QuantityCannotBeNegativeError"
                }
            ]
        }
    }
}
System Errors
When a system error occurs, users typically can't resolve it themselves, but it's still important to notify them that something has gone wrong.
The onCompleted callback's second argument is an array of errors from the GraphQL response, which includes non-critical errors.
{
  "data": {
      "addToBasket": {
          "shoppingBasket": null,
          "errors": null
      }
  },
  "errors" : [
    {
      "message": "Unepxected execution error"
    }
  ]
}
The errors listed here are not marked as CRITICAL.
Critical errors, which prevent Relay from functioning properly, trigger the onError callback. Examples of critical errors include:
- Network issues like 503, 404, or 500 errors
 - JSON parsing errors, such as when the server returns invalid JSON
 - Situations where the server returns an empty 
datafield 
{
  "errors" : [
    {
      "message": "Unepxected execution error"
    }
  ]
}
These critical issues are managed by the onError callback of the useMutation hook:
  onError: (err) => console.error(err) ,
Tasks
- Try to follow the steps outlined in this lesson and add error handling to the 
addToBasketmutation - Add error handling to the mutation in the 
cart.tsxfile aswell - Open the network tab in the browser and slow down the network. How is the user experience if you change the quantity of a product in the basket?