mirror of
https://github.com/vuejs/apollo.git
synced 2025-12-08 18:02:09 +00:00
feat: convert errors into ApolloError (#1225)
This commit is contained in:
parent
08b6b0e7d9
commit
334310d5e6
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -4,5 +4,6 @@
|
|||||||
"javascriptreact",
|
"javascriptreact",
|
||||||
"vue"
|
"vue"
|
||||||
],
|
],
|
||||||
"eslint.enable": true
|
"eslint.enable": true,
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import { DocumentNode } from 'graphql'
|
import { DocumentNode } from 'graphql'
|
||||||
import { MutationOptions, OperationVariables, FetchResult, TypedDocumentNode } from '@apollo/client/core'
|
import { MutationOptions, OperationVariables, FetchResult, TypedDocumentNode, ApolloError } from '@apollo/client/core'
|
||||||
import { ref, onBeforeUnmount, isRef, Ref, getCurrentInstance } from 'vue-demi'
|
import { ref, onBeforeUnmount, isRef, Ref, getCurrentInstance } from 'vue-demi'
|
||||||
import { useApolloClient } from './useApolloClient'
|
import { useApolloClient } from './useApolloClient'
|
||||||
import { ReactiveFunction } from './util/ReactiveFunction'
|
import { ReactiveFunction } from './util/ReactiveFunction'
|
||||||
import { useEventHook } from './util/useEventHook'
|
import { useEventHook } from './util/useEventHook'
|
||||||
import { trackMutation } from './util/loadingTracking'
|
import { trackMutation } from './util/loadingTracking'
|
||||||
|
import { toApolloError } from './util/toApolloError'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `useMutation` options for mutations that don't require `variables`.
|
* `useMutation` options for mutations that don't require `variables`.
|
||||||
@ -27,12 +28,12 @@ export type MutateFunction<TResult, TVariables> = (variables?: TVariables | null
|
|||||||
export interface UseMutationReturn<TResult, TVariables> {
|
export interface UseMutationReturn<TResult, TVariables> {
|
||||||
mutate: MutateFunction<TResult, TVariables>
|
mutate: MutateFunction<TResult, TVariables>
|
||||||
loading: Ref<boolean>
|
loading: Ref<boolean>
|
||||||
error: Ref<Error | null>
|
error: Ref<ApolloError | null>
|
||||||
called: Ref<boolean>
|
called: Ref<boolean>
|
||||||
onDone: (fn: (param: FetchResult<TResult, Record<string, any>, Record<string, any>>) => void) => {
|
onDone: (fn: (param: FetchResult<TResult, Record<string, any>, Record<string, any>>) => void) => {
|
||||||
off: () => void
|
off: () => void
|
||||||
}
|
}
|
||||||
onError: (fn: (param: Error) => void) => {
|
onError: (fn: (param: ApolloError) => void) => {
|
||||||
off: () => void
|
off: () => void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,11 +48,11 @@ export function useMutation<
|
|||||||
const vm = getCurrentInstance()
|
const vm = getCurrentInstance()
|
||||||
const loading = ref<boolean>(false)
|
const loading = ref<boolean>(false)
|
||||||
vm && trackMutation(loading)
|
vm && trackMutation(loading)
|
||||||
const error = ref<Error | null>(null)
|
const error = ref<ApolloError | null>(null)
|
||||||
const called = ref<boolean>(false)
|
const called = ref<boolean>(false)
|
||||||
|
|
||||||
const doneEvent = useEventHook<FetchResult<TResult, Record<string, any>, Record<string, any>>>()
|
const doneEvent = useEventHook<FetchResult<TResult, Record<string, any>, Record<string, any>>>()
|
||||||
const errorEvent = useEventHook<Error>()
|
const errorEvent = useEventHook<ApolloError>()
|
||||||
|
|
||||||
// Apollo Client
|
// Apollo Client
|
||||||
const { resolveClient } = useApolloClient()
|
const { resolveClient } = useApolloClient()
|
||||||
@ -94,11 +95,12 @@ export function useMutation<
|
|||||||
doneEvent.trigger(result)
|
doneEvent.trigger(result)
|
||||||
return result
|
return result
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error.value = e
|
const apolloError = toApolloError(e)
|
||||||
|
error.value = apolloError
|
||||||
loading.value = false
|
loading.value = false
|
||||||
errorEvent.trigger(e)
|
errorEvent.trigger(apolloError)
|
||||||
if (currentOptions.throws === 'always' || (currentOptions.throws !== 'never' && !errorEvent.getCount())) {
|
if (currentOptions.throws === 'always' || (currentOptions.throws !== 'never' && !errorEvent.getCount())) {
|
||||||
throw e
|
throw apolloError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import {
|
|||||||
FetchMoreOptions,
|
FetchMoreOptions,
|
||||||
ObservableSubscription,
|
ObservableSubscription,
|
||||||
TypedDocumentNode,
|
TypedDocumentNode,
|
||||||
|
ApolloError,
|
||||||
} from '@apollo/client/core'
|
} from '@apollo/client/core'
|
||||||
import { throttle, debounce } from 'throttle-debounce'
|
import { throttle, debounce } from 'throttle-debounce'
|
||||||
import { useApolloClient } from './useApolloClient'
|
import { useApolloClient } from './useApolloClient'
|
||||||
@ -28,6 +29,7 @@ import { paramToRef } from './util/paramToRef'
|
|||||||
import { paramToReactive } from './util/paramToReactive'
|
import { paramToReactive } from './util/paramToReactive'
|
||||||
import { useEventHook } from './util/useEventHook'
|
import { useEventHook } from './util/useEventHook'
|
||||||
import { trackQuery } from './util/loadingTracking'
|
import { trackQuery } from './util/loadingTracking'
|
||||||
|
import { toApolloError } from './util/toApolloError'
|
||||||
|
|
||||||
import type { CurrentInstance } from './util/types'
|
import type { CurrentInstance } from './util/types'
|
||||||
|
|
||||||
@ -58,7 +60,7 @@ export interface UseQueryReturn<TResult, TVariables> {
|
|||||||
result: Ref<TResult | undefined>
|
result: Ref<TResult | undefined>
|
||||||
loading: Ref<boolean>
|
loading: Ref<boolean>
|
||||||
networkStatus: Ref<number | undefined>
|
networkStatus: Ref<number | undefined>
|
||||||
error: Ref<Error | null>
|
error: Ref<ApolloError | null>
|
||||||
start: () => void
|
start: () => void
|
||||||
stop: () => void
|
stop: () => void
|
||||||
restart: () => void
|
restart: () => void
|
||||||
@ -73,7 +75,7 @@ export interface UseQueryReturn<TResult, TVariables> {
|
|||||||
onResult: (fn: (param: ApolloQueryResult<TResult>) => void) => {
|
onResult: (fn: (param: ApolloQueryResult<TResult>) => void) => {
|
||||||
off: () => void
|
off: () => void
|
||||||
}
|
}
|
||||||
onError: (fn: (param: Error) => void) => {
|
onError: (fn: (param: ApolloError) => void) => {
|
||||||
off: () => void
|
off: () => void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,8 +156,8 @@ export function useQueryImpl<
|
|||||||
*/
|
*/
|
||||||
const result = ref<TResult | undefined>()
|
const result = ref<TResult | undefined>()
|
||||||
const resultEvent = useEventHook<ApolloQueryResult<TResult>>()
|
const resultEvent = useEventHook<ApolloQueryResult<TResult>>()
|
||||||
const error = ref<Error | null>(null)
|
const error = ref<ApolloError | null>(null)
|
||||||
const errorEvent = useEventHook<Error>()
|
const errorEvent = useEventHook<ApolloError>()
|
||||||
|
|
||||||
// Loading
|
// Loading
|
||||||
|
|
||||||
@ -168,7 +170,7 @@ export function useQueryImpl<
|
|||||||
|
|
||||||
// SSR
|
// SSR
|
||||||
let firstResolve: (() => void) | undefined
|
let firstResolve: (() => void) | undefined
|
||||||
let firstReject: ((error: Error) => void) | undefined
|
let firstReject: ((apolloError: ApolloError) => void) | undefined
|
||||||
onServerPrefetch?.(() => {
|
onServerPrefetch?.(() => {
|
||||||
if (!isEnabled.value || (isServer && currentOptions.value?.prefetch === false)) return
|
if (!isEnabled.value || (isServer && currentOptions.value?.prefetch === false)) return
|
||||||
|
|
||||||
@ -178,8 +180,8 @@ export function useQueryImpl<
|
|||||||
firstResolve = undefined
|
firstResolve = undefined
|
||||||
firstReject = undefined
|
firstReject = undefined
|
||||||
}
|
}
|
||||||
firstReject = (error: Error) => {
|
firstReject = (apolloError: ApolloError) => {
|
||||||
reject(error)
|
reject(apolloError)
|
||||||
firstResolve = undefined
|
firstResolve = undefined
|
||||||
firstReject = undefined
|
firstReject = undefined
|
||||||
}
|
}
|
||||||
@ -258,15 +260,10 @@ export function useQueryImpl<
|
|||||||
|
|
||||||
processNextResult(queryResult)
|
processNextResult(queryResult)
|
||||||
|
|
||||||
// Result errors
|
// ApolloQueryResult.error may be set at the same time as we get a result
|
||||||
// This is set when `errorPolicy` is `all`
|
// when `errorPolicy` is `all`
|
||||||
if (queryResult.errors?.length) {
|
if (queryResult.error !== undefined) {
|
||||||
const e = new Error(`GraphQL error: ${queryResult.errors.map(e => e.message).join(' | ')}`)
|
processError(queryResult.error)
|
||||||
Object.assign(e, {
|
|
||||||
graphQLErrors: queryResult.errors,
|
|
||||||
networkError: null,
|
|
||||||
})
|
|
||||||
processError(e)
|
|
||||||
} else {
|
} else {
|
||||||
if (firstResolve) {
|
if (firstResolve) {
|
||||||
firstResolve()
|
firstResolve()
|
||||||
@ -282,22 +279,25 @@ export function useQueryImpl<
|
|||||||
resultEvent.trigger(queryResult)
|
resultEvent.trigger(queryResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onError (queryError: any) {
|
function onError (queryError: unknown) {
|
||||||
|
// any error should already be an ApolloError, but we make sure
|
||||||
|
const apolloError = toApolloError(queryError)
|
||||||
|
|
||||||
processNextResult((query.value as ObservableQuery<TResult, TVariables>).getCurrentResult())
|
processNextResult((query.value as ObservableQuery<TResult, TVariables>).getCurrentResult())
|
||||||
processError(queryError)
|
processError(apolloError)
|
||||||
if (firstReject) {
|
if (firstReject) {
|
||||||
firstReject(queryError)
|
firstReject(apolloError)
|
||||||
stop()
|
stop()
|
||||||
}
|
}
|
||||||
// The observable closes the sub if an error occurs
|
// The observable closes the sub if an error occurs
|
||||||
resubscribeToQuery()
|
resubscribeToQuery()
|
||||||
}
|
}
|
||||||
|
|
||||||
function processError (queryError: any) {
|
function processError (apolloError: ApolloError) {
|
||||||
error.value = queryError
|
error.value = apolloError
|
||||||
loading.value = false
|
loading.value = false
|
||||||
networkStatus.value = 8
|
networkStatus.value = 8
|
||||||
errorEvent.trigger(queryError)
|
errorEvent.trigger(apolloError)
|
||||||
}
|
}
|
||||||
|
|
||||||
function resubscribeToQuery () {
|
function resubscribeToQuery () {
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import {
|
|||||||
Observable,
|
Observable,
|
||||||
ObservableSubscription,
|
ObservableSubscription,
|
||||||
TypedDocumentNode,
|
TypedDocumentNode,
|
||||||
|
ApolloError,
|
||||||
} from '@apollo/client/core'
|
} from '@apollo/client/core'
|
||||||
import { throttle, debounce } from 'throttle-debounce'
|
import { throttle, debounce } from 'throttle-debounce'
|
||||||
import { ReactiveFunction } from './util/ReactiveFunction'
|
import { ReactiveFunction } from './util/ReactiveFunction'
|
||||||
@ -26,6 +27,7 @@ import { useEventHook } from './util/useEventHook'
|
|||||||
import { trackSubscription } from './util/loadingTracking'
|
import { trackSubscription } from './util/loadingTracking'
|
||||||
|
|
||||||
import type { CurrentInstance } from './util/types'
|
import type { CurrentInstance } from './util/types'
|
||||||
|
import { toApolloError } from './util/toApolloError'
|
||||||
|
|
||||||
export interface UseSubscriptionOptions <
|
export interface UseSubscriptionOptions <
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
@ -45,7 +47,7 @@ type OptionsParameter<TResult, TVariables> = UseSubscriptionOptions<TResult, TVa
|
|||||||
export interface UseSubscriptionReturn<TResult, TVariables> {
|
export interface UseSubscriptionReturn<TResult, TVariables> {
|
||||||
result: Ref<TResult | null | undefined>
|
result: Ref<TResult | null | undefined>
|
||||||
loading: Ref<boolean>
|
loading: Ref<boolean>
|
||||||
error: Ref<Error | null>
|
error: Ref<ApolloError | null>
|
||||||
start: () => void
|
start: () => void
|
||||||
stop: () => void
|
stop: () => void
|
||||||
restart: () => void
|
restart: () => void
|
||||||
@ -56,7 +58,7 @@ export interface UseSubscriptionReturn<TResult, TVariables> {
|
|||||||
onResult: (fn: (param: FetchResult<TResult, Record<string, any>, Record<string, any>>) => void) => {
|
onResult: (fn: (param: FetchResult<TResult, Record<string, any>, Record<string, any>>) => void) => {
|
||||||
off: () => void
|
off: () => void
|
||||||
}
|
}
|
||||||
onError: (fn: (param: Error) => void) => {
|
onError: (fn: (param: ApolloError) => void) => {
|
||||||
off: () => void
|
off: () => void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,8 +121,8 @@ export function useSubscription <
|
|||||||
|
|
||||||
const result = ref<TResult | null | undefined>()
|
const result = ref<TResult | null | undefined>()
|
||||||
const resultEvent = useEventHook<FetchResult<TResult>>()
|
const resultEvent = useEventHook<FetchResult<TResult>>()
|
||||||
const error = ref<Error | null>(null)
|
const error = ref<ApolloError | null>(null)
|
||||||
const errorEvent = useEventHook<Error>()
|
const errorEvent = useEventHook<ApolloError>()
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
vm && trackSubscription(loading)
|
vm && trackSubscription(loading)
|
||||||
@ -157,10 +159,12 @@ export function useSubscription <
|
|||||||
resultEvent.trigger(fetchResult)
|
resultEvent.trigger(fetchResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onError (fetchError: any) {
|
function onError (fetchError: unknown) {
|
||||||
error.value = fetchError
|
const apolloError = toApolloError(fetchError)
|
||||||
|
|
||||||
|
error.value = apolloError
|
||||||
loading.value = false
|
loading.value = false
|
||||||
errorEvent.trigger(fetchError)
|
errorEvent.trigger(apolloError)
|
||||||
}
|
}
|
||||||
|
|
||||||
function stop () {
|
function stop () {
|
||||||
|
|||||||
16
packages/vue-apollo-composable/src/util/toApolloError.ts
Normal file
16
packages/vue-apollo-composable/src/util/toApolloError.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { ApolloError, isApolloError } from '@apollo/client'
|
||||||
|
|
||||||
|
export function toApolloError (error: unknown): ApolloError {
|
||||||
|
if (!(error instanceof Error)) {
|
||||||
|
return new ApolloError({
|
||||||
|
networkError: Object.assign(new Error(), { originalError: error }),
|
||||||
|
errorMessage: String(error),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isApolloError(error)) {
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ApolloError({ networkError: error, errorMessage: error.message })
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user