Skip to content

Commit 5e6b51d

Browse files
committed
adjust types, add test
1 parent 58f0c46 commit 5e6b51d

File tree

6 files changed

+69
-50
lines changed

6 files changed

+69
-50
lines changed

src/core/QueryInfo.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { DocumentNode } from "graphql";
1+
import type { DocumentNode, GraphQLFormattedError } from "graphql";
22
import { equal } from "@wry/equality";
33

44
import type { Cache, ApolloCache } from "../cache/index.js";
@@ -15,10 +15,7 @@ import {
1515
canUseWeakMap,
1616
} from "../utilities/index.js";
1717
import { NetworkStatus, isNetworkRequestInFlight } from "./networkStatus.js";
18-
import type {
19-
ApolloError,
20-
GraphQLErrorsFromResponse,
21-
} from "../errors/index.js";
18+
import type { ApolloError } from "../errors/index.js";
2219
import type { QueryManager } from "./QueryManager.js";
2320

2421
export type QueryStoreValue = Pick<
@@ -85,7 +82,7 @@ export class QueryInfo {
8582
variables?: Record<string, any>;
8683
networkStatus?: NetworkStatus;
8784
networkError?: Error | null;
88-
graphQLErrors?: GraphQLErrorsFromResponse;
85+
graphQLErrors?: ReadonlyArray<GraphQLFormattedError>;
8986
stopped = false;
9087

9188
private cache: ApolloCache<any>;

src/errors/__tests__/ApolloError.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ApolloError } from "..";
2-
import { GraphQLError } from "graphql";
2+
import { ExecutableDefinitionNode, GraphQLError, parse, Source } from "graphql";
33

44
describe("ApolloError", () => {
55
it("should construct itself correctly", () => {
@@ -107,4 +107,38 @@ describe("ApolloError", () => {
107107
});
108108
expect(apolloError.stack).toBeDefined();
109109
});
110+
111+
it("will revive `GraphQLError` instances from `graphQLErrors`", () => {
112+
const source = new Source(`
113+
{
114+
field
115+
}
116+
`);
117+
const ast = parse(source);
118+
const operationNode = ast.definitions[0] as ExecutableDefinitionNode;
119+
const fieldNode = operationNode.selectionSet.selections[0];
120+
const original = new GraphQLError("msg" /* message */, {
121+
nodes: [fieldNode],
122+
source,
123+
positions: [1, 2, 3],
124+
path: ["a", "b", "c"],
125+
originalError: new Error("test"),
126+
extensions: { foo: "bar" },
127+
});
128+
129+
const apolloError = new ApolloError({
130+
graphQLErrors: [JSON.parse(JSON.stringify(original))],
131+
});
132+
const graphQLError = apolloError.graphQLErrors[0];
133+
134+
console.log({
135+
graphQLError,
136+
original,
137+
serialized: JSON.stringify(original),
138+
});
139+
140+
expect(graphQLError).toBeInstanceOf(GraphQLError);
141+
// test equality of enumberable fields. non-enumerable fields will differ
142+
expect({ ...graphQLError }).toStrictEqual({ ...original });
143+
});
110144
});

src/errors/index.ts

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import "../utilities/globals/index.js";
22

3-
import type { GraphQLErrorExtensions } from "graphql";
3+
import type { GraphQLErrorExtensions, GraphQLFormattedError } from "graphql";
44
import { GraphQLError } from "graphql";
55

66
import { isNonNullObject } from "../utilities/index.js";
@@ -18,7 +18,7 @@ type FetchResultWithSymbolExtensions<T> = FetchResult<T> & {
1818
};
1919

2020
export interface ApolloErrorOptions {
21-
graphQLErrors?: GraphQLErrorsFromResponse;
21+
graphQLErrors?: ReadonlyArray<GraphQLFormattedError>;
2222
protocolErrors?: ReadonlyArray<{
2323
message: string;
2424
extensions?: GraphQLErrorExtensions[];
@@ -68,25 +68,14 @@ const generateErrorMessage = (err: ApolloError) => {
6868
);
6969
};
7070

71-
/**
72-
* A GraphQLError, as received from the server in a GraphQL Response
73-
*
74-
* See https://github.com/graphql/graphql-spec/blob/main/spec/Section%207%20--%20Response.md#errors
75-
* (scroll down to Error Result Format)
76-
* Only `message` is mandatory in the spec, the other fields are optional.
77-
*/
78-
export type GraphQLErrorFromResponse = Pick<GraphQLError, "message"> &
79-
Partial<GraphQLError>;
80-
export type GraphQLErrorsFromResponse = ReadonlyArray<GraphQLErrorFromResponse>;
81-
8271
export type GraphQLErrors = ReadonlyArray<GraphQLError>;
8372

8473
export type NetworkError = Error | ServerParseError | ServerError | null;
8574

8675
export class ApolloError extends Error {
8776
public name: string;
8877
public message: string;
89-
public graphQLErrors: GraphQLErrorsFromResponse;
78+
public graphQLErrors: GraphQLError[];
9079
public protocolErrors: ReadonlyArray<{
9180
message: string;
9281
extensions?: GraphQLErrorExtensions[];
@@ -132,7 +121,7 @@ export class ApolloError extends Error {
132121
this.cause =
133122
[
134123
networkError,
135-
...(graphQLErrors || []),
124+
...(this.graphQLErrors || []),
136125
...(protocolErrors || []),
137126
...(clientErrors || []),
138127
].find((e) => !!e) || null;
@@ -149,16 +138,18 @@ export class ApolloError extends Error {
149138
* spec, but they are not optional in the `GraphQLError` type.
150139
* This function ensures that all errors are instances of the `GraphQLError` class.
151140
*/
152-
export function reviveGraphQLError(
153-
error: GraphQLErrorFromResponse
154-
): GraphQLError {
141+
export function reviveGraphQLError(error: GraphQLFormattedError): GraphQLError {
155142
return error instanceof GraphQLError ? error : (
156-
new GraphQLError(
157-
error.message,
158-
// This will pass `message` into the `options` parameter.
159-
// The constructor does not expect that, but it will ignore it and we
160-
// don't need to destructure `error`, saving some bundle size.
161-
error
143+
Object.assign(
144+
new GraphQLError(
145+
error.message,
146+
// This will pass `message` into the `options` parameter.
147+
// The constructor does not expect that, but it will ignore it and we
148+
// don't need to destructure `error`, saving some bundle size.
149+
error
150+
),
151+
//
152+
{ locations: error.locations }
162153
)
163154
);
164155
}

src/link/core/types.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import type { GraphQLError } from "graphql";
1+
import type { GraphQLError, GraphQLFormattedError } from "graphql";
22
import type { DocumentNode } from "graphql";
33
import type { DefaultContext } from "../../core/index.js";
44
export type { DocumentNode };
55

66
import type { Observable } from "../../utilities/index.js";
7-
import type { GraphQLErrorsFromResponse } from "../../errors/index.js";
87

98
export type Path = ReadonlyArray<string | number>;
109

@@ -96,7 +95,7 @@ export interface SingleExecutionResult<
9695
// data might be undefined if errorPolicy was set to 'ignore'
9796
data?: TData | null;
9897
context?: TContext;
99-
errors?: GraphQLErrorsFromResponse;
98+
errors?: ReadonlyArray<GraphQLFormattedError>;
10099
extensions?: TExtensions;
101100
}
102101

src/link/error/index.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
import type { ExecutionResult } from "graphql";
1+
import type { ExecutionResult, GraphQLFormattedError } from "graphql";
22

3-
import type {
4-
NetworkError,
5-
GraphQLErrorsFromResponse,
6-
} from "../../errors/index.js";
3+
import type { NetworkError } from "../../errors/index.js";
74
import { Observable } from "../../utilities/index.js";
85
import type { Operation, FetchResult, NextLink } from "../core/index.js";
96
import { ApolloLink } from "../core/index.js";
107

118
export interface ErrorResponse {
12-
graphQLErrors?: GraphQLErrorsFromResponse;
9+
graphQLErrors?: ReadonlyArray<GraphQLFormattedError>;
1310
networkError?: NetworkError;
1411
response?: ExecutionResult;
1512
operation: Operation;

src/link/persisted-queries/index.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import { invariant } from "../../utilities/globals/index.js";
22

33
import { print } from "../../utilities/index.js";
4-
import type { DocumentNode, ExecutionResult, GraphQLError } from "graphql";
4+
import type {
5+
DocumentNode,
6+
ExecutionResult,
7+
GraphQLError,
8+
GraphQLFormattedError,
9+
} from "graphql";
510

611
import type { Operation } from "../core/index.js";
712
import { ApolloLink } from "../core/index.js";
@@ -10,11 +15,7 @@ import type {
1015
ObservableSubscription,
1116
} from "../../utilities/index.js";
1217
import { Observable, compact, isNonEmptyArray } from "../../utilities/index.js";
13-
import type {
14-
GraphQLErrorFromResponse,
15-
GraphQLErrorsFromResponse,
16-
NetworkError,
17-
} from "../../errors/index.js";
18+
import type { NetworkError } from "../../errors/index.js";
1819
import type { ServerError } from "../utils/index.js";
1920
import {
2021
cacheSizes,
@@ -25,7 +26,7 @@ import {
2526
export const VERSION = 1;
2627

2728
export interface ErrorResponse {
28-
graphQLErrors?: GraphQLErrorsFromResponse;
29+
graphQLErrors?: ReadonlyArray<GraphQLFormattedError>;
2930
networkError?: NetworkError;
3031
response?: ExecutionResult;
3132
operation: Operation;
@@ -64,8 +65,8 @@ export namespace PersistedQueryLink {
6465

6566
function processErrors(
6667
graphQLErrors:
67-
| GraphQLErrorFromResponse[]
68-
| readonly GraphQLErrorFromResponse[]
68+
| GraphQLFormattedError[]
69+
| ReadonlyArray<GraphQLFormattedError>
6970
| undefined
7071
): ErrorMeta {
7172
const byMessage = Object.create(null),
@@ -187,7 +188,7 @@ export const createPersistedQueryLink = (
187188
if (!retried && ((response && response.errors) || networkError)) {
188189
retried = true;
189190

190-
const graphQLErrors: GraphQLErrorFromResponse[] = [];
191+
const graphQLErrors: GraphQLFormattedError[] = [];
191192

192193
const responseErrors = response && response.errors;
193194
if (isNonEmptyArray(responseErrors)) {

0 commit comments

Comments
 (0)