Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
at main 3.9 kB view raw
1import { GraphQLError } from '@0no-co/graphql.web'; 2import type { ErrorLike } from '../types'; 3 4const generateErrorMessage = ( 5 networkErr?: Error, 6 graphQlErrs?: GraphQLError[] 7) => { 8 let error = ''; 9 if (networkErr) return `[Network] ${networkErr.message}`; 10 if (graphQlErrs) { 11 for (let i = 0, l = graphQlErrs.length; i < l; i++) { 12 if (error) error += '\n'; 13 error += `[GraphQL] ${graphQlErrs[i].message}`; 14 } 15 } 16 return error; 17}; 18 19const rehydrateGraphQlError = (error: any): GraphQLError => { 20 if ( 21 error && 22 typeof error.message === 'string' && 23 (error.extensions || error.name === 'GraphQLError') 24 ) { 25 return error; 26 } else if (typeof error === 'object' && typeof error.message === 'string') { 27 return new GraphQLError( 28 error.message, 29 error.nodes, 30 error.source, 31 error.positions, 32 error.path, 33 error, 34 error.extensions || {} 35 ); 36 } else { 37 return new GraphQLError(error as any); 38 } 39}; 40 41/** An abstracted `Error` that provides either a `networkError` or `graphQLErrors`. 42 * 43 * @remarks 44 * During a GraphQL request, either the request can fail entirely, causing a network error, 45 * or the GraphQL execution or fields can fail, which will cause an {@link ExecutionResult} 46 * to contain an array of GraphQL errors. 47 * 48 * The `CombinedError` abstracts and normalizes both failure cases. When {@link OperationResult.error} 49 * is set to this error, the `CombinedError` abstracts all errors, making it easier to handle only 50 * a subset of error cases. 51 * 52 * @see {@link https://urql.dev/goto/docs/basics/errors} for more information on handling 53 * GraphQL errors and the `CombinedError`. 54 */ 55export class CombinedError extends Error { 56 public name: string; 57 public message: string; 58 59 /** A list of GraphQL errors rehydrated from a {@link ExecutionResult}. 60 * 61 * @remarks 62 * If an {@link ExecutionResult} received from the API contains a list of errors, 63 * the `CombinedError` will rehydrate them, normalize them to 64 * {@link GraphQLError | GraphQLErrors} and list them here. 65 * An empty list indicates that no GraphQL error has been sent by the API. 66 */ 67 public graphQLErrors: GraphQLError[]; 68 69 /** Set to an error, if a GraphQL request has failed outright. 70 * 71 * @remarks 72 * A GraphQL over HTTP request may fail and not reach the API. Any error that 73 * prevents a GraphQl request outright, will be considered a “network error” and 74 * set here. 75 */ 76 public networkError?: Error; 77 78 /** Set to the {@link Response} object a fetch exchange received. 79 * 80 * @remarks 81 * If a built-in fetch {@link Exchange} is used in `urql`, this may 82 * be set to the {@link Response} object of the Fetch API response. 83 * However, since `urql` doesn’t assume that all users will use HTTP 84 * as the only or exclusive transport for GraphQL this property is 85 * neither typed nor guaranteed and may be re-used for other purposes 86 * by non-fetch exchanges. 87 * 88 * Hint: It can be useful to use `response.status` here, however, if 89 * you plan on relying on this being a {@link Response} in your app, 90 * which it is by default, then make sure you add some extra checks 91 * before blindly assuming so! 92 */ 93 public response?: any; 94 95 constructor(input: { 96 networkError?: Error; 97 graphQLErrors?: Array<string | ErrorLike>; 98 response?: any; 99 }) { 100 const normalizedGraphQLErrors = (input.graphQLErrors || []).map( 101 rehydrateGraphQlError 102 ); 103 const message = generateErrorMessage( 104 input.networkError, 105 normalizedGraphQLErrors 106 ); 107 108 super(message); 109 110 this.name = 'CombinedError'; 111 this.message = message; 112 this.graphQLErrors = normalizedGraphQLErrors; 113 this.networkError = input.networkError; 114 this.response = input.response; 115 } 116 117 toString(): string { 118 return this.message; 119 } 120}