Error handling

You probably noticed that both useQuery and useMutation return an error field. This page is about how to handle it and different types of errors it represents.

Draqula exposes two kinds of errors:

  • NetworkError - Network or timeout errors
  • GraphQLError - Errors originating from resolvers on the GraphQL server

Most of the time you won't need such granular error handling and checking for error existence should be enough for most use-cases, but this functionality is still important to document, so here we go.

Network errors

A network error can occur in many cases, like when a request has timed out or the server responded with 4xx/5xx HTTP status codes. Draqula wraps network and timeout errors into NetworkError for your convenience. However, the original error from ky-universal (The HTTP client that Draqula uses) can still be retrieved via the originalError property.

To detect a network error, check if it's an instance of NetworkError:

1 import {NetworkError} from 'draqula';
2
3 const Todos = () => {
4 const {data, isLoading, error} = useQuery(TODOS_QUERY);
5
6 if (error instanceof NetworkError) {
7 // Network error!
8 }
9
10 // ...
11};

If you need more specific information about the error, you can import error types from [ky-universal] and check it:

1 import {NetworkError} from 'draqula';
2 import {HTTPError, TimeoutError} from 'ky-universal';
3
4 const Todos = () => {
5 const {data, isLoading, error} = useQuery(TODOS_QUERY);
6
7 if (error instanceof NetworkError) {
8 if (error.originalError instanceof HTTPError) {
9 // Most likely a 4xx or 5xx status code
10 }
11
12 if (error.originalError instanceof TimeoutError) {
13 // Request has timed out
14 }
15 }
16
17 // ...
18};

GraphQL errors

GraphQLError is a pretty unusual error in JavaScript land, because it actually represents multiple errors at once. The reason for this custom functionality is that a single GraphQL request can respond with multiple errors at the same time. If Draqula didn't care about you as much, it would probably just expose this:

1const {data, isLoading, errors} = useQuery()

Then you'd have to check if the errors array's length is more than zero and handle network and GraphQL errors manually. Thankfully, that's not the case. Draqula combines all errors into one object and sets error's message property to equal the message of the first error returned from server.

1 import {GraphQLError} from 'draqula';
2
3 const Todos = () => {
4 const {data, isLoading, error} = useQuery(TODOS_QUERY);
5
6 if (error instanceof GraphQLError) {
7 // GraphQL error, resolvers failed!
8 alert(error.message);
9 }
10
11 // ...
12};

Keep in mind though, that GraphQLError is a "bundle" error that contains multiple errors inside. So if you expect multiple errors per query, you need to convert error returned from useQuery into an array and iterate it to display all of them.

1 import {GraphQLError} from 'draqula';
2
3 const Todos = () => {
4 const {data, isLoading, error} = useQuery(TODOS_QUERY);
5
6 return (
7 <>
8 {error instanceof GraphQLError &&
9 error.toArray().map((graphqlError, index) => (
10 <div key={index} style={{color: 'red'}}>
11 {graphqlError.message}
12 </div>
13 ))}
14 </>
15 );
16};

Alternatively, it's possible to iterate error itself with for..of.

1 import {GraphQLError} from 'draqula';
2
3 const Todos = () => {
4 const {data, isLoading, error} = useQuery(TODOS_QUERY);
5
6 if (error instanceof GraphQLError) {
7 for (const graphqlError of error) {
8 // Please don't actually alert error messages, it's for demo purposes only
9 alert(graphqlError.message);
10 }
11 }
12
13 // ...
14};