Skip to content

Commit

Permalink
fix(client): wrap all subscription errors in QueryResults
Browse files Browse the repository at this point in the history
  • Loading branch information
micimize committed Nov 9, 2020
1 parent 7eb3f58 commit aae61ca
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 30 deletions.
72 changes: 42 additions & 30 deletions packages/graphql/lib/src/core/query_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'package:meta/meta.dart';
import 'package:collection/collection.dart';

import 'package:gql_exec/gql_exec.dart';
import 'package:gql_link/gql_link.dart' show Link;
import 'package:gql_link/gql_link.dart' show Link, LinkException;

import 'package:graphql/src/cache/cache.dart';
import 'package:graphql/src/core/observable_query.dart';
Expand Down Expand Up @@ -75,39 +75,45 @@ class QueryManager {
}
}

yield* link.request(request).map((response) {
QueryResult queryResult;
bool rereadFromCache = false;
try {
queryResult = mapFetchResultToQueryResult(
response,
options,
source: QueryResultSource.network,
);
try {
yield* link.request(request).map((response) {
QueryResult queryResult;
bool rereadFromCache = false;
try {
queryResult = mapFetchResultToQueryResult(
response,
options,
source: QueryResultSource.network,
);

rereadFromCache = attemptCacheWriteFromResponse(
options.fetchPolicy,
request,
response,
queryResult,
);
} catch (failure) {
// we set the source to indicate where the source of failure
queryResult ??= QueryResult(source: QueryResultSource.network);
rereadFromCache = attemptCacheWriteFromResponse(
options.fetchPolicy,
request,
response,
queryResult,
);
} catch (failure) {
// we set the source to indicate where the source of failure
queryResult ??= QueryResult(source: QueryResultSource.network);

queryResult.exception = coalesceErrors(
exception: queryResult.exception,
linkException: translateFailure(failure),
);
}
queryResult.exception = coalesceErrors(
exception: queryResult.exception,
linkException: translateFailure(failure),
);
}

if (rereadFromCache) {
// normalize results if previously written
attempCacheRereadIntoResult(request, queryResult);
}
if (rereadFromCache) {
// normalize results if previously written
attempCacheRereadIntoResult(request, queryResult);
}

return queryResult;
});
return queryResult;
}).transform(StreamTransformer.fromHandlers(
handleError: (err, trace, sink) => sink.add(_wrapFailure(err)),
));
} catch (ex) {
yield* Stream.fromIterable([_wrapFailure(ex)]);
}
}

Future<QueryResult> query(QueryOptions options) => fetchQuery('0', options);
Expand Down Expand Up @@ -476,3 +482,9 @@ class QueryManager {
);
}
}

QueryResult _wrapFailure(dynamic ex) => QueryResult(
// we set the source to indicate where the source of failure
source: QueryResultSource.network,
exception: coalesceErrors(linkException: translateFailure(ex)),
);
76 changes: 76 additions & 0 deletions packages/graphql/test/graphql_client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,82 @@ void main() {
),
);
});

test('wraps stream exceptions', () async {
final ex = ServerException(
parsedResponse: null,
originalException: Error(),
);

when(
link.request(any),
).thenAnswer(
(_) => Stream.error(ex),
);

final stream = client.subscribe(
SubscriptionOptions(
document: parseString(
r'''
subscription {
item {
id
name
}
}
''',
),
),
);

expect(
stream,
emitsInOrder(
[
isA<QueryResult>().having(
(result) => result.exception.linkException,
'wrapped exception',
ex,
),
],
),
);
});
test('wraps all exceptions from outside of stream', () async {
final err = Error();

when(
link.request(any),
).thenThrow(err);

final stream = client.subscribe(
SubscriptionOptions(
document: parseString(
r'''
subscription {
item {
id
name
}
}
''',
),
),
);

expect(
stream,
emitsInOrder(
[
isA<QueryResult>().having(
(result) => result.exception.linkException.originalException,
'wrapped exception',
err,
),
],
),
);
});
});
});

Expand Down

0 comments on commit aae61ca

Please sign in to comment.