gql_error_link 1.0.1-alpha+1709845491490 gql_error_link: ^1.0.1-alpha+1709845491490 copied to clipboard
GQL Link to handle execution errors and exceptions
GQL Link to handle execution errors and exceptions.
Usage #
An example using ErrorLink
to act on auth exceptions.
Note that this example is very inefficient because it not only updates token on every request, it does so only after the request has failed first. A more feature complete example of an auth link can be found here.
import "package:gql/language.dart";
import "package:gql_error_link/gql_error_link.dart";
import "package:gql_exec/gql_exec.dart";
import "package:gql_link/gql_link.dart";
// Let's imagine we have some terminating [Link]
final terminatingLink = Link.function(
(request, [forward]) async* {
// It expects [AuthToken] to be present in the context.
final token = request.context.entry<AuthToken>();
// If token is not present, it throws [AuthException].
if (token == null) {
throw AuthException();
}
// Otherwise, yield some [Response].
yield Response(
data: <String, String>{
"magic": token.token,
},
);
},
);
// In this case [AuthToken] is a simple container of a [String] token.
class AuthToken extends ContextEntry {
final String token;
const AuthToken({this.token});
@override
List<Object> get fieldsForEquality => [];
}
// Our terminating link defines it's own [AuthException]
class AuthException extends ServerException {}
// We have some means of getting a new valid token
Future<String> getNewToken() => Future.delayed(
Duration(milliseconds: 10),
() => "Valid token",
);
// We'll want to handle [LinkException]s
Stream<Response> handleException(
Request request,
NextLink forward,
LinkException exception,
) async* {
// If the exception is [AuthException]
if (exception is AuthException) {
// We fetch a new token
final token = await getNewToken();
// Update the request with the new token
final updatedRequest = request.withContextEntry(
AuthToken(token: token),
);
// And try the request again
yield* forward(updatedRequest);
return;
}
// Otherwise, we rethrow the previous exception
throw exception;
}
void main() async {
// We use the [ErrorLink] by prepending it before the terminating link
final link = Link.from([
ErrorLink(onException: handleException),
terminatingLink,
]);
try {
// Let's fetch the first Response
final response = await link
.request(
Request(
operation: Operation(
document: parseString("{}"),
),
),
)
.first;
// Internally the first response was an exception, but [ErrorLink] caught
// it and retried the request with a valid token
print(response.data);
} catch (e) {
// This was not even called
print(e);
}
}
Features and bugs #
Please file feature requests and bugs at the GitHub.