Global error handling with vue-query

Aron Schüler Published


TLDR

Too much to read? Here's a summary of the article.

  1. Use vue-query with axios as the http client.

  2. Create an axios instance and set up interceptors to handle errors.

  3. Use the axios instance in vue-query’s useQuery and useMutation hooks.

  4. When an error occurs, send a notification to a toast store.

Introduction

What is Tanstack Query and Vue-Query?

Tanstack Query is a data fetching and caching library for JavaScript and TypeScript. It provides a set of tools for managing, caching, and updating server state in your application. Vue-Query is a Vue-specific implementation of Tanstack Query, which makes it easy to integrate with Vue applications.

I wrote about dealing with enriching Sentry errors when working with react-query in a previous blog post. This time I want to show how to handle errors on a global level with Vue-Query.

The Problem

When working with Vue-Query, you can handle errors on a component or global level. For non-specific errors like internal server errors, it makes sense to use global error handling. This means that we want to be able to catch and handle errors that occur during data fetching and caching, and display a notification to the user when an error occurs.

The Solution

One way to handle errors on a global level in Vue-Query is to use interceptors, when using Axios as the HTTP client for fetching data from the server. Axios interceptors allow you to intercept requests and responses, and thereby catch and handle errors that occur during data fetching. By using Axios interceptors, we will send a notification to our toast store when a server error occurs.

Understanding Vue-Query

What is Vue-Query?

@tanstack/vue-query is the Vue-specific implementation of Tanstack Query. It provides the benefits of Tanstack Query, but with a Vue-specific API and integration. Vue-Query makes it easy to integrate data fetching and caching into your Vue applications.

The Role and Importance of Vue-Query in Vue Apps

With Vue-Query, we add a layer of abstraction to our data fetching and caching logic. This allows us to manage server state in a more predictable and efficient way. Vue-Query provides a set of hooks that make it easy to fetch and cache data, and to handle loading and error states. Without Vue-Query, we would have to write a lot of boilerplate code to manage server state, such as caching, loading, and error handling. This would make our codebase more complex and harder to maintain, and it would be difficult to keep track of the state of our data.

Common Cases Where Errors Are Likely to Occur with Vue-Query

While using Vue-Query, errors can occur in various scenarios, such as when fetching data from the server, submitting input data to the server, or when dealing with state mismatches. These errors can be due to network issues, server issues, or client-side issues. It is important to handle these errors in a consistent and predictable way, and to provide a good user experience when an error occurs. Some of these errors should be handled in the component where they occur, while others should be handled on a global level.

An Intro to Axios and Interceptors

What is Axios and Its Role in Vue?

Axios is a popular HTTP client for making requests to a server from a client-side application. It is widely used in web applications across all frameworks, including Vue. Axios provides a simple and consistent API for making HTTP requests, and it is easy to integrate with Vue applications.

What are Axios Interceptors?

Axios interceptors are functions that can be used to intercept requests and responses before they are handled by the application. This allows you to modify requests and responses, and to catch and handle errors that occur during data fetching. Axios interceptors are a powerful tool for managing server state in a predictable and efficient way.

How to Set Up Axios Interceptors

Let’s start by creating an Axios instance that we will use to make requests to the server, set up interceptors to handle errors and send a notification to our toast store when an error occurs.

This could look something like this:

import axios from "axios";

const customAxiosInstance = axios.create({
  baseURL: "https://api.example.com",
});

const sendNotification = (error) => {
  // Send a notification to your toast store here.
};

customAxiosInstance.interceptors.response.use(
  (response) => response,
  (error) => {
    sendNotification(error);
    return Promise.reject(error);
  },
);

export default customAxiosInstance;

In this example, we create an Axios instance with a base URL of https://api.example.com. We then set up an interceptor to catch and handle errors that occur during data fetching. When an error occurs, we send a notification to our toast store, and then reject the promise so that the error can be handled further down the line.

Integrating Axios Interceptors with Vue-Query

Now that we have set up an Axios instance with interceptors to handle errors, we can use this instance in Vue-Query’s useQuery and useMutation hooks to fetch and cache data from the server.

Here’s an example of how to use the Axios instance in a useQuery hook:

import { useQuery } from "@tanstack/vue-query";
import customAxiosInstance from "./customAxiosInstance";

const useGetUser = (userId) => {
  return useQuery(
    ["user", userId],
    customAxiosInstance.get(`/users/${userId}`),
  );
};

In this example, we create a useGetUser hook that uses the Axios instance to fetch data from the server. We pass the Axios instance to the useQuery hook as the second argument, and the hook takes care of the rest. This way, we can use the Axios instance in all of our useQuery and useMutation hooks to handle errors on a global level. When an error occurs, the interceptor will catch and handle the error, and send a notification to our toast store. As the Promise is still rejected, you can still handle errors on a component level, e.g. in v4 of vue-query, you can use the onError callback to handle errors on a component level.

How to Handle Server Errors

When a server error occurs, we want to send a notification to our toast store to inform the user that an error has occurred. We can do this by calling a function that sends a notification to our toast store from the interceptor. You can filter for different types of errors and send different notifications based on the error type.

Here’s an example of how to send a notification translated with vue-i18n to our toast store when a server error occurs:

const sendNotification = (error: AxiosError) => {
  // We want to handle server errors on a global level,
  // so we send a notification to our toast store here.
  if (error.response?.status.toString().startsWith("5")) {
    const { t } = i18n.global;
    let text = t("apiErrors.general");
    if (error.response?.data?.description) {
      text = error.response.data.description;
    }
    if (error.response?.status === 500) {
      text = t("apiErrors.internal");
    }
    if (error.response?.status === 501) {
      text = t("apiErrors.notImplemented");
    }
    if (error.response?.status === 502) {
      text = t("apiErrors.badGateway");
    }
    if (error.response?.status === 503) {
      text = t("apiErrors.serviceUnavailable");
    }
    if (error.response?.status === 504) {
      text = t("apiErrors.gatewayTimeout");
    }

    toastStore.error({ text });
  }

  return Promise.reject(error);
};

In this example, we create a function called sendNotification that takes an Axios error as an argument. We then check the status code of the error response, and send a translated notification to our toast store based on the status code. This way, we can provide a good user experience when a server error occurs, and inform the user that an error has occurred.

Conclusion

In this blog post, we have learned how to handle errors on a global level with Vue-Query by using Axios interceptors. We have set up an Axios instance with interceptors to catch and handle errors that occur during data fetching, and send a notification to our toast store when an error occurs. By using Axios interceptors, we can handle errors on a global level, and provide a good user experience when an error occurs.

If you have any comments or questions, feel free to leave a comment below. I’d love to hear your thoughts on this topic!


Related Posts

Find posts on similar topics:


Comments