Skip to content

Commit 99d72bf

Browse files
authored
Add a new helper that detects network errors from the link chain (#12561)
* Inline type of network error in persisted-queries * Remove NetworkError type in errors/index * Add a NetworkError class * Add tests for NetworkError * Add tsdoc * Add equality tester for NetworkError * Export isErrorLike * Leave cause as raw value in NetworkError * Add a link that wraps errors with NetworkError * Update exports snapshot * Add changeset * Rerun api report * Update size limits * Move isErrorLike to own file * Update api report * Update size limits * Update doc * Remove equality matcher * Remove NetworkError from is tests * Update NetworkError to be a facade object that registers errors * Register network errors from the link chain * Register errors from mutations * Handle mutations * Handle subscriptions * Add watchQuery check * Create separate internal function * Update exports snapshot * Remove network error link * Update exports snapshot * Update api report * Update size limits * Remove outdated file * Export NetworkError in core * Update changeset * Add failing test case for mutations * Wrap and register network error sooner in the chain * Remove need to check CombinedGraphQLErrors * Rename NetworkError to LinkError * Add type to WeakSet * Update changeset * Rerun api report * Update size limits * Update exports snapshot
1 parent 90bf0e6 commit 99d72bf

File tree

15 files changed

+374
-40
lines changed

15 files changed

+374
-40
lines changed

.api-reports/api-report-core.api.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import { InMemoryCacheConfig } from '@apollo/client/cache';
5959
import type { InteropObservable } from 'rxjs';
6060
import { isReference } from '@apollo/client/utilities';
6161
import type { IsStrictlyAny } from '@apollo/client/utilities';
62+
import { LinkError } from '@apollo/client/errors';
6263
import { makeReference } from '@apollo/client/utilities';
6364
import { makeVar } from '@apollo/client/cache';
6465
import { Masked } from '@apollo/client/masking';
@@ -406,6 +407,8 @@ export function isNetworkRequestSettled(networkStatus?: NetworkStatus): boolean;
406407

407408
export { isReference }
408409

410+
export { LinkError }
411+
409412
// @public (undocumented)
410413
class LocalState {
411414
// Warning: (ae-forgotten-export) The symbol "LocalStateOptions" needs to be exported by the entry point index.d.ts
@@ -1113,8 +1116,8 @@ export type WatchQueryOptions<TVariables extends OperationVariables = OperationV
11131116
// src/core/ObservableQuery.ts:84:5 - (ae-forgotten-export) The symbol "NextFetchPolicyContext" needs to be exported by the entry point index.d.ts
11141117
// src/core/ObservableQuery.ts:190:5 - (ae-forgotten-export) The symbol "QueryManager" needs to be exported by the entry point index.d.ts
11151118
// src/core/ObservableQuery.ts:191:5 - (ae-forgotten-export) The symbol "QueryInfo" needs to be exported by the entry point index.d.ts
1116-
// src/core/QueryManager.ts:186:5 - (ae-forgotten-export) The symbol "MutationStoreValue" needs to be exported by the entry point index.d.ts
1117-
// src/core/QueryManager.ts:456:7 - (ae-forgotten-export) The symbol "UpdateQueries" needs to be exported by the entry point index.d.ts
1119+
// src/core/QueryManager.ts:187:5 - (ae-forgotten-export) The symbol "MutationStoreValue" needs to be exported by the entry point index.d.ts
1120+
// src/core/QueryManager.ts:455:7 - (ae-forgotten-export) The symbol "UpdateQueries" needs to be exported by the entry point index.d.ts
11181121
// src/core/watchQueryOptions.ts:262:3 - (ae-forgotten-export) The symbol "IgnoreModifier" needs to be exported by the entry point index.d.ts
11191122

11201123
// (No @packageDocumentation comment for this package)

.api-reports/api-report-errors.api.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
```ts
66

7-
import type { ErrorLike } from '@apollo/client';
7+
import { ErrorLike } from '@apollo/client';
88
import type { FetchResult } from '@apollo/client/link/core';
99
import type { FetchResult as FetchResult_2 } from '@apollo/client';
1010
import type { GraphQLFormattedError } from 'graphql';
@@ -62,12 +62,17 @@ type FetchResultWithSymbolExtensions<T> = FetchResult<T> & {
6262
// @public (undocumented)
6363
export function graphQLResultHasProtocolErrors<T>(result: FetchResult<T>): result is FetchResultWithSymbolExtensions<T>;
6464

65-
// @public (undocumented)
66-
export type NetworkError = Error | ServerParseError | ServerError | null;
65+
// @public
66+
export const LinkError: {
67+
is: (error: unknown) => boolean;
68+
};
6769

6870
// @public (undocumented)
6971
export const PROTOCOL_ERRORS_SYMBOL: unique symbol;
7072

73+
// @internal
74+
export function registerLinkError(error: ErrorLike): void;
75+
7176
// @public
7277
export class ServerError extends Error {
7378
// Warning: (ae-forgotten-export) The symbol "ServerErrorOptions" needs to be exported by the entry point index.d.ts

.api-reports/api-report-link_persisted-queries.api.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import { ApolloLink } from '@apollo/client/link/core';
88
import type { DocumentNode } from 'graphql';
99
import type { FormattedExecutionResult } from 'graphql';
1010
import type { GraphQLFormattedError } from 'graphql';
11-
import type { NetworkError } from '@apollo/client/errors';
1211
import type { Operation } from '@apollo/client/link/core';
12+
import type { ServerError } from '@apollo/client/errors';
13+
import type { ServerParseError } from '@apollo/client/errors';
1314

1415
// @public (undocumented)
1516
interface BaseOptions {
@@ -49,7 +50,7 @@ export interface ErrorResponse {
4950
// (undocumented)
5051
meta: ErrorMeta;
5152
// (undocumented)
52-
networkError?: NetworkError;
53+
networkError?: Error | ServerParseError | ServerError | null;
5354
// (undocumented)
5455
operation: Operation;
5556
// (undocumented)

.api-reports/api-report-react.api.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,8 +1609,8 @@ type WatchQueryOptions_2<TVariables extends OperationVariables_2 = OperationVari
16091609
// src/core/ObservableQuery.ts:96:5 - (ae-forgotten-export) The symbol "RefetchWritePolicy" needs to be exported by the entry point index.d.ts
16101610
// src/core/ObservableQuery.ts:190:5 - (ae-forgotten-export) The symbol "QueryManager" needs to be exported by the entry point index.d.ts
16111611
// src/core/ObservableQuery.ts:191:5 - (ae-forgotten-export) The symbol "QueryInfo" needs to be exported by the entry point index.d.ts
1612-
// src/core/QueryManager.ts:186:5 - (ae-forgotten-export) The symbol "MutationStoreValue" needs to be exported by the entry point index.d.ts
1613-
// src/core/QueryManager.ts:456:7 - (ae-forgotten-export) The symbol "UpdateQueries" needs to be exported by the entry point index.d.ts
1612+
// src/core/QueryManager.ts:187:5 - (ae-forgotten-export) The symbol "MutationStoreValue" needs to be exported by the entry point index.d.ts
1613+
// src/core/QueryManager.ts:455:7 - (ae-forgotten-export) The symbol "UpdateQueries" needs to be exported by the entry point index.d.ts
16141614
// src/core/types.ts:201:3 - (ae-forgotten-export) The symbol "MutationQueryReducer" needs to be exported by the entry point index.d.ts
16151615
// src/core/types.ts:230:5 - (ae-forgotten-export) The symbol "Resolver" needs to be exported by the entry point index.d.ts
16161616
// src/core/watchQueryOptions.ts:186:3 - (ae-forgotten-export) The symbol "UpdateQueryOptions" needs to be exported by the entry point index.d.ts

.api-reports/api-report.api.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,11 @@ class Layer extends EntityStore {
12941294
toObject(): NormalizedCacheObject;
12951295
}
12961296

1297+
// @public
1298+
export const LinkError: {
1299+
is: (error: unknown) => boolean;
1300+
};
1301+
12971302
// @public (undocumented)
12981303
class LocalState {
12991304
// Warning: (ae-forgotten-export) The symbol "LocalStateOptions" needs to be exported by the entry point index.d.ts
@@ -2533,8 +2538,8 @@ interface WriteContext extends ReadMergeModifyContext {
25332538
// src/core/ObservableQuery.ts:84:5 - (ae-forgotten-export) The symbol "NextFetchPolicyContext" needs to be exported by the entry point index.d.ts
25342539
// src/core/ObservableQuery.ts:190:5 - (ae-forgotten-export) The symbol "QueryManager" needs to be exported by the entry point index.d.ts
25352540
// src/core/ObservableQuery.ts:191:5 - (ae-forgotten-export) The symbol "QueryInfo" needs to be exported by the entry point index.d.ts
2536-
// src/core/QueryManager.ts:186:5 - (ae-forgotten-export) The symbol "MutationStoreValue" needs to be exported by the entry point index.d.ts
2537-
// src/core/QueryManager.ts:456:7 - (ae-forgotten-export) The symbol "UpdateQueries" needs to be exported by the entry point index.d.ts
2541+
// src/core/QueryManager.ts:187:5 - (ae-forgotten-export) The symbol "MutationStoreValue" needs to be exported by the entry point index.d.ts
2542+
// src/core/QueryManager.ts:455:7 - (ae-forgotten-export) The symbol "UpdateQueries" needs to be exported by the entry point index.d.ts
25382543
// src/core/watchQueryOptions.ts:262:3 - (ae-forgotten-export) The symbol "IgnoreModifier" needs to be exported by the entry point index.d.ts
25392544
// src/link/http/selectHttpOptionsAndBody.ts:128:1 - (ae-forgotten-export) The symbol "HttpQueryOptions" needs to be exported by the entry point index.d.ts
25402545

.changeset/odd-chicken-hide.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
"@apollo/client": minor
3+
---
4+
5+
Add the ability to detect if an error was an error was emitted from the link chain. This is useful if your application throws custom errors in other areas of the application and you'd like to differentiate them from errors emitted by the link chain itself.
6+
7+
To detect if an error was emitted from the link chain, use `LinkError.is`.
8+
9+
```ts
10+
import { LinkError } from "@apollo/client";
11+
12+
client.query({ query }).catch((error) => {
13+
if (LinkError.is(error)) {
14+
// This error originated from the link chain
15+
}
16+
});
17+
```

.size-limits.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (CJS)": 43269,
3-
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production) (CJS)": 38762,
4-
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\"": 33223,
5-
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production)": 28027
2+
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (CJS)": 43438,
3+
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production) (CJS)": 38878,
4+
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\"": 33207,
5+
"import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production)": 28023
66
}

src/__tests__/__snapshots__/exports.ts.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Array [
1010
"DocumentTransform",
1111
"HttpLink",
1212
"InMemoryCache",
13+
"LinkError",
1314
"MissingFieldError",
1415
"NetworkStatus",
1516
"Observable",
@@ -77,6 +78,7 @@ Array [
7778
"DocumentTransform",
7879
"HttpLink",
7980
"InMemoryCache",
81+
"LinkError",
8082
"MissingFieldError",
8183
"NetworkStatus",
8284
"Observable",
@@ -129,11 +131,13 @@ exports[`exports of public entry points @apollo/client/errors 1`] = `
129131
Array [
130132
"CombinedGraphQLErrors",
131133
"CombinedProtocolErrors",
134+
"LinkError",
132135
"PROTOCOL_ERRORS_SYMBOL",
133136
"ServerError",
134137
"ServerParseError",
135138
"UnconventionalError",
136139
"graphQLResultHasProtocolErrors",
140+
"registerLinkError",
137141
"toErrorLike",
138142
]
139143
`;

src/core/QueryManager.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { canonicalStringify } from "@apollo/client/cache";
2525
import {
2626
CombinedGraphQLErrors,
2727
graphQLResultHasProtocolErrors,
28+
registerLinkError,
2829
toErrorLike,
2930
} from "@apollo/client/errors";
3031
import { PROTOCOL_ERRORS_SYMBOL } from "@apollo/client/errors";
@@ -411,9 +412,7 @@ export class QueryManager {
411412
}
412413
},
413414

414-
error: (err) => {
415-
const error = toErrorLike(err);
416-
415+
error: (error) => {
417416
if (mutationStoreValue) {
418417
mutationStoreValue.loading = false;
419418
mutationStoreValue.error = error;
@@ -1100,7 +1099,7 @@ export class QueryManager {
11001099
return of({ data: undefined } as SubscribeResult<TData>);
11011100
}
11021101

1103-
return of({ data: undefined, error: toErrorLike(error) });
1102+
return of({ data: undefined, error });
11041103
}),
11051104
filter((result) => !!(result.data || result.error))
11061105
);
@@ -1233,7 +1232,13 @@ export class QueryManager {
12331232
);
12341233
}
12351234

1236-
return observable;
1235+
return observable.pipe(
1236+
catchError((error) => {
1237+
error = toErrorLike(error);
1238+
registerLinkError(error);
1239+
throw error;
1240+
})
1241+
);
12371242
}
12381243

12391244
private getResultsFromLink<TData, TVariables extends OperationVariables>(
@@ -1307,8 +1312,6 @@ export class QueryManager {
13071312
return aqr;
13081313
}),
13091314
catchError((error) => {
1310-
error = toErrorLike(error);
1311-
13121315
// Avoid storing errors from older interrupted queries.
13131316
if (requestId >= queryInfo.lastRequestId && errorPolicy === "none") {
13141317
queryInfo.resetLastWrite();

src/core/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export type { FragmentMatcher, Resolver } from "./LocalState.js";
5454
export {
5555
CombinedGraphQLErrors,
5656
CombinedProtocolErrors,
57+
LinkError,
5758
ServerError,
5859
ServerParseError,
5960
UnconventionalError,

0 commit comments

Comments
 (0)