Skip to content

Commit e7396ee

Browse files
committed
Add ApolloErrorHandlerResult class, refactor types
1 parent 766bd54 commit e7396ee

File tree

9 files changed

+171
-126
lines changed

9 files changed

+171
-126
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import {
2+
ApolloErrorType,
3+
InputValidationError,
4+
NetworkError,
5+
ProcessedApolloError,
6+
ServerError,
7+
UnauthorizedError,
8+
UserInputError,
9+
ValidationRuleViolation,
10+
} from './types';
11+
12+
export interface ApolloErrorHandlerResultInterface {
13+
processedErrors: ProcessedApolloError[];
14+
validationRuleViolations?: ValidationRuleViolation[];
15+
}
16+
17+
export class ApolloErrorHandlerResult implements ApolloErrorHandlerResultInterface {
18+
public constructor(
19+
public readonly processedErrors: ProcessedApolloError[],
20+
public readonly handledErrors: ProcessedApolloError[],
21+
) {}
22+
23+
public get networkErrors(): NetworkError[] {
24+
return this.processedErrors.filter((e): e is NetworkError => e.type === ApolloErrorType.NETWORK_ERROR);
25+
}
26+
27+
public get serverErrors(): ServerError[] {
28+
return this.processedErrors.filter((e): e is ServerError => e.type === ApolloErrorType.SERVER_ERROR);
29+
}
30+
31+
public get unauthorizedErrors(): UnauthorizedError[] {
32+
return this.processedErrors.filter((e): e is UnauthorizedError => e.type === ApolloErrorType.UNAUTHORIZED_ERROR);
33+
}
34+
35+
public get userInputErrors(): UserInputError[] {
36+
return this.processedErrors.filter((e): e is UserInputError => e.type === ApolloErrorType.BAD_USER_INPUT);
37+
}
38+
39+
public get inputValidationErrors(): InputValidationError[] {
40+
return this.processedErrors.filter(
41+
(e): e is InputValidationError => e.type === ApolloErrorType.INPUT_VALIDATION_ERROR,
42+
);
43+
}
44+
45+
public get validationRuleViolations(): ValidationRuleViolation[] {
46+
return this.inputValidationErrors.flatMap(e => e.violations);
47+
}
48+
}

src/error/ApolloErrorProcessor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import Vue from 'vue';
2+
import { ApolloOperationContext } from '../types';
23
import {
34
ApolloError,
45
ApolloErrorType,
5-
ApolloOperationContext,
66
GraphQLError,
77
InputValidationError,
88
ProcessedApolloError,
99
ServerError,
1010
UnauthorizedError,
11-
} from '../types';
11+
} from './types';
1212

1313
export function isApolloError(error: ApolloError | any): error is ApolloError {
1414
return error.graphQLErrors !== undefined;

src/error/handleApolloError.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import { ApolloErrorProcessor } from './ApolloErrorProcessor';
2-
import {
3-
ApolloError,
4-
ApolloErrorHandlerResult,
5-
ApolloOperationContext,
6-
ApolloOperationErrorHandlerFunction,
7-
} from '../types';
2+
import { ApolloOperationContext } from '../types';
83
import { Vue } from 'vue/types/vue';
4+
import { ApolloError, ApolloOperationErrorHandlerFunction } from './types';
5+
import { ApolloErrorHandlerResultInterface } from './ApolloErrorHandlerResult';
96

107
/**
118
* This is a simple example of an error handler function. You can copy this and implement your own in your application.
@@ -14,7 +11,7 @@ export const handleApolloError: ApolloOperationErrorHandlerFunction<ApolloError,
1411
error: ApolloError,
1512
app: Vue,
1613
context?: ApolloOperationContext,
17-
): ApolloErrorHandlerResult => {
14+
): ApolloErrorHandlerResultInterface => {
1815
const processor = new ApolloErrorProcessor(error, app, context ?? {});
1916

2017
processor.showErrorNotifications();

src/error/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@
22
* @file Automatically generated by barrelsby.
33
*/
44

5+
export * from './ApolloErrorHandlerResult';
56
export * from './ApolloErrorProcessor';
67
export * from './handleApolloError';
8+
export * from './types';

src/error/types.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { GraphQLError as BaseGraphQLError } from 'graphql';
2+
import { ApolloError as BaseApolloError } from 'apollo-client';
3+
import { Vue } from 'vue/types/vue';
4+
import { ApolloOperationContext } from '../types';
5+
import { ApolloErrorHandlerResultInterface } from './ApolloErrorHandlerResult';
6+
7+
export enum ApolloErrorType {
8+
NETWORK_ERROR = 'NETWORK_ERROR',
9+
SERVER_ERROR = 'SERVER_ERROR',
10+
UNAUTHORIZED_ERROR = 'UNAUTHORIZED_ERROR',
11+
BAD_USER_INPUT = 'BAD_USER_INPUT',
12+
INPUT_VALIDATION_ERROR = 'INPUT_VALIDATION_ERROR',
13+
}
14+
15+
// Upstream type declares networkError as Error, but it can contain additional properties, we override to add these
16+
export type ApolloError = BaseApolloError & {
17+
networkError: ApolloNetworkError | null;
18+
graphQLErrors: GraphQLError[];
19+
};
20+
21+
export interface ApolloNetworkError extends Error {
22+
statusCode?: number;
23+
response?: any;
24+
result?: {
25+
errors: GraphQLError[];
26+
};
27+
}
28+
29+
export type GraphQLError = Omit<BaseGraphQLError, 'message'> & {
30+
message: string | Record<string, any>;
31+
};
32+
export type ProcessedApolloError =
33+
| NetworkError
34+
| ServerError
35+
| UnauthorizedError
36+
| UserInputError
37+
| InputValidationError;
38+
39+
export interface NetworkError {
40+
type: ApolloErrorType.NETWORK_ERROR;
41+
error: Error;
42+
message: string;
43+
statusCode?: number;
44+
}
45+
46+
export interface ServerError {
47+
type: ApolloErrorType.SERVER_ERROR;
48+
error: Error;
49+
path?: readonly (string | number)[];
50+
message: string;
51+
}
52+
53+
export interface UnauthorizedError {
54+
type: ApolloErrorType.UNAUTHORIZED_ERROR;
55+
error: Error;
56+
path?: readonly (string | number)[];
57+
message: string;
58+
}
59+
60+
export interface UserInputError {
61+
type: ApolloErrorType.BAD_USER_INPUT;
62+
error: Error;
63+
path?: readonly (string | number)[];
64+
message: string;
65+
}
66+
67+
export interface InputValidationError {
68+
type: ApolloErrorType.INPUT_VALIDATION_ERROR;
69+
error: Error;
70+
path?: readonly (string | number)[];
71+
message: string;
72+
invalidArgs: string[];
73+
violations: ValidationRuleViolation[];
74+
}
75+
76+
export interface ValidationRuleViolation {
77+
path: string[];
78+
message: string;
79+
value?: any;
80+
}
81+
82+
export type ApolloOperationErrorHandlerFunction<
83+
TError = BaseApolloError,
84+
TApp extends Vue = Vue,
85+
TContext = ApolloOperationContext,
86+
> = (error: TError, app: TApp, context?: TContext) => ApolloErrorHandlerResultInterface;

src/mutation.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ import { FetchPolicy, MutationBaseOptions } from 'apollo-client/core/watchQueryO
66
import { Vue } from 'vue/types/vue';
77
import mapValues from 'lodash.mapvalues';
88
import isPlainObject from 'lodash.isplainobject';
9+
import { ApolloOperationContext } from './types';
910
import {
10-
ApolloErrorHandlerResult,
11-
ApolloOperationContext,
11+
ApolloErrorHandlerResultInterface,
1212
ApolloOperationErrorHandlerFunction,
1313
ProcessedApolloError,
1414
ValidationRuleViolation,
15-
} from './types';
15+
} from './error';
1616

1717
export type ApolloComponentMutationFunction<R = any, TVariables = OperationVariables> = (
1818
options: MutationBaseOptions<R, TVariables> &
@@ -108,7 +108,7 @@ export async function mutateWithErrorHandling<
108108
return { success: true, data: result.data };
109109
} catch (error) {
110110
const { onError, context } = params;
111-
const errorHandlerResult: ApolloErrorHandlerResult | undefined =
111+
const errorHandlerResult: ApolloErrorHandlerResultInterface | undefined =
112112
onError != null ? onError(error, app, context) : undefined;
113113

114114
return {

src/query.ts

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,9 @@
11
import { ApolloError, OperationVariables } from 'apollo-client';
22
import { DocumentNode } from 'graphql';
3-
import { ErrorHandler, VueApolloQueryDefinition, VueApolloSubscribeToMoreOptions } from 'vue-apollo/types/options';
3+
import { ErrorHandler, VueApolloQueryDefinition } from 'vue-apollo/types/options';
44
import { Vue } from 'vue/types/vue';
5-
import { ApolloOperationErrorHandlerFunction } from './types';
6-
7-
type OverrideThis<F, T> = F extends (...args: infer A) => infer B ? (this: T, ...args: A) => B : F;
8-
9-
type OverrideAllThis<O, T> = {
10-
[key in keyof O]: OverrideThis<O[key], T>;
11-
};
12-
13-
type SubscribeToMoreOptionsPatched<TComponent, TResult, TVariables> = OverrideAllThis<
14-
Omit<VueApolloSubscribeToMoreOptions<TResult, TVariables>, 'updateQuery' | 'variables'>,
15-
TComponent
16-
> & {
17-
variables?: (this: TComponent) => any;
18-
updateQuery?: UpdateQueryFn<TComponent, TResult, any, any>; // TODO: How should we pass subscript data & variables types?
19-
};
20-
21-
type UpdateQueryFn<TComponent = any, TResult = any, TSubscriptionVariables = any, TSubscriptionData = any> = (
22-
this: TComponent,
23-
previousQueryResult: TResult,
24-
options: {
25-
subscriptionData: {
26-
data: TSubscriptionData;
27-
};
28-
variables?: TSubscriptionVariables;
29-
},
30-
) => TResult;
5+
import { ApolloOperationErrorHandlerFunction } from './error';
6+
import { OverrideAllThis, SubscribeToMoreOptionsPatched } from './types';
317

328
export interface VueApolloQueryDefinitionPatched<TComponent extends Vue = Vue, TResult = any, TVariables = any>
339
extends OverrideAllThis<

src/subscription.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ErrorHandler, VueApolloSubscriptionDefinition } from 'vue-apollo/types/
22
import { ApolloError, OperationVariables } from 'apollo-client';
33
import { DocumentNode } from 'graphql';
44
import { Vue } from 'vue/types/vue';
5-
import { ApolloOperationErrorHandlerFunction } from './types';
5+
import { ApolloOperationErrorHandlerFunction } from './error';
66

77
export type VueApolloSmartSubscriptionErrorHandler<
88
TResult = any,

src/types.ts

Lines changed: 21 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,28 @@
1-
import { ApolloError as BaseApolloError } from 'apollo-client';
2-
import { Vue } from 'vue/types/vue';
3-
import { GraphQLError as BaseGraphQLError } from 'graphql';
1+
import { VueApolloSubscribeToMoreOptions } from 'vue-apollo/types/options';
42

5-
export type ApolloOperationContext<TAttrs = Record<string, any>> = TAttrs;
6-
7-
export enum ApolloErrorType {
8-
NETWORK_ERROR = 'NETWORK_ERROR',
9-
SERVER_ERROR = 'SERVER_ERROR',
10-
UNAUTHORIZED_ERROR = 'UNAUTHORIZED_ERROR',
11-
BAD_USER_INPUT = 'BAD_USER_INPUT',
12-
INPUT_VALIDATION_ERROR = 'INPUT_VALIDATION_ERROR',
13-
}
3+
type OverrideThis<F, T> = F extends (...args: infer A) => infer B ? (this: T, ...args: A) => B : F;
144

15-
// Upstream type declares networkError as Error, but it can contain additional properties, we override to add these
16-
export type ApolloError = BaseApolloError & {
17-
networkError: ApolloNetworkError | null;
18-
graphQLErrors: GraphQLError[];
5+
export type OverrideAllThis<O, T> = {
6+
[key in keyof O]: OverrideThis<O[key], T>;
197
};
208

21-
export interface ApolloNetworkError extends Error {
22-
statusCode?: number;
23-
response?: any;
24-
result?: {
25-
errors: GraphQLError[];
26-
};
27-
}
28-
29-
export type GraphQLError = Omit<BaseGraphQLError, 'message'> & {
30-
message: string | Record<string, any>;
9+
export type SubscribeToMoreOptionsPatched<TComponent, TResult, TVariables> = OverrideAllThis<
10+
Omit<VueApolloSubscribeToMoreOptions<TResult, TVariables>, 'updateQuery' | 'variables'>,
11+
TComponent
12+
> & {
13+
variables?: (this: TComponent) => any;
14+
updateQuery?: UpdateQueryFn<TComponent, TResult, any, any>; // TODO: How should we pass subscript data & variables types?
3115
};
3216

33-
export type ProcessedApolloError =
34-
| NetworkError
35-
| ServerError
36-
| UnauthorizedError
37-
| UserInputError
38-
| InputValidationError;
39-
40-
export interface NetworkError {
41-
type: ApolloErrorType.NETWORK_ERROR;
42-
error: Error;
43-
message: string;
44-
statusCode?: number;
45-
}
46-
47-
export interface ServerError {
48-
type: ApolloErrorType.SERVER_ERROR;
49-
error: Error;
50-
path?: readonly (string | number)[];
51-
message: string;
52-
}
53-
54-
export interface UnauthorizedError {
55-
type: ApolloErrorType.UNAUTHORIZED_ERROR;
56-
error: Error;
57-
path?: readonly (string | number)[];
58-
message: string;
59-
}
17+
type UpdateQueryFn<TComponent = any, TResult = any, TSubscriptionVariables = any, TSubscriptionData = any> = (
18+
this: TComponent,
19+
previousQueryResult: TResult,
20+
options: {
21+
subscriptionData: {
22+
data: TSubscriptionData;
23+
};
24+
variables?: TSubscriptionVariables;
25+
},
26+
) => TResult;
6027

61-
export interface UserInputError {
62-
type: ApolloErrorType.BAD_USER_INPUT;
63-
error: Error;
64-
path?: readonly (string | number)[];
65-
message: string;
66-
}
67-
68-
export interface InputValidationError {
69-
type: ApolloErrorType.INPUT_VALIDATION_ERROR;
70-
error: Error;
71-
path?: readonly (string | number)[];
72-
message: string;
73-
invalidArgs: string[];
74-
violations: ValidationRuleViolation[];
75-
}
76-
77-
export interface ValidationRuleViolation {
78-
path: string[];
79-
message: string;
80-
value?: any;
81-
}
82-
83-
export interface ApolloErrorHandlerResult {
84-
processedErrors: ProcessedApolloError[];
85-
validationRuleViolations?: ValidationRuleViolation[];
86-
}
87-
88-
export type ApolloOperationErrorHandlerFunction<
89-
TError = BaseApolloError,
90-
TApp extends Vue = Vue,
91-
TContext = ApolloOperationContext,
92-
> = (error: TError, app: TApp, context?: TContext) => ApolloErrorHandlerResult;
28+
export type ApolloOperationContext<TAttrs = Record<string, any>> = TAttrs;

0 commit comments

Comments
 (0)