Reputation: 199
I'm using graphql_flutter
package and want to have a interceptor for that,
for access token i want to get new token when my request responded with 401 response code.
Upvotes: 8
Views: 4358
Reputation: 9103
GraphQl itself doesn't have such interceptor, and they are not willing to as per this thread. Instead you can use requests_inspector package that can be used with graphql library:
To use requests_inspector with graphql_flutter library. you jus need to wrap your normal HttpLink with our GraphQLInspectorLink and we are done.
final client = GraphQLClient(
cache: GraphQLCache(),
link: Link.split(
(request) => request.isSubscription,
GraphQLInspectorLink(WebSocketLink('ws://graphqlzero.almansi.me/api')),
GraphQLInspectorLink(HttpLink('https://graphqlzero.almansi.me/api')),
),
);
But this package seems like they don't provide a callback method, but another weird method to get the request details by "shaking your phone", I'm not sure if there is another descent way to achieve that using this package or no, if not you can fork the same package to achieve your goal.
Upvotes: 1
Reputation: 837
Inside the (builder:{}) you can use if (result.hasException) {}, this will trigger automatically when you get a error from the graphql. so, do check that error is JWT expire. you can check this by result.exception.toString(). Then you can run the other mutation to refresh to token then re-initialize the client.
Upvotes: 1
Reputation: 607
i think its better to use a global error handler widget that you can call with yout Query widget
here is my example error handler
final _appstate = getIt.get<AppState>();
class ExceptionBuilder extends StatelessWidget {
final OperationException exception;
final bool hasData;
final VoidCallback refetch;
const ExceptionBuilder(
{Key key,
@required this.exception,
@required this.hasData,
@required this.refetch})
: super(key: key);
Widget _resolver(BuildContext context) {
if ((exception.linkException is LinkException)) {
return SliverFillRemaining(
hasScrollBody: false,
child: Center(
child: Column(mainAxisSize: MainAxisSize.min, children: [
emptyList(context, icon: Icons.wifi_off, msg: "Network Error"),
FlatButton(
onPressed: refetch,
child: Text(
"retry",
style: TextStyle(color: accentColor),
))
]),
),
);
} else if (exception.graphqlErrors.isNotEmpty) {
List<String> _errors = exception.graphqlErrors[0].message.split(':');
if (_errors[1] == " JWTExpired") {
_appstate.refreshToken();
return SliverFillRemaining(
hasScrollBody: false,
child: Container(
alignment: Alignment.center,
child: masker(context, Loader()),
));
}
return SliverFillRemaining(
hasScrollBody: false,
child: Column(mainAxisSize: MainAxisSize.min, children: [
emptyList(context,
icon: Icons.warning_amber_rounded, msg: "Something went wrong"),
FlatButton(
onPressed: refetch,
child: Text(
"retry",
style: TextStyle(color: accentColor),
))
]),
);
}
return SliverToBoxAdapter(
child: SizedBox.shrink(),
);
}
@override
Widget build(BuildContext context) {
return _resolver(context);
}
}
I am using sliver widget because i am calling it in CustomScrollView
here is the resolver method
List<Widget> _resolver(BuildContext context, QueryResult result,
FetchMore fetchMore, Refetch refetch) {
if (result.isLoading && isNull(result.data)) {
return [
SliverFillRemaining(
hasScrollBody: false,
child: Container(
alignment: Alignment.center,
child: masker(context, Loader()),
))
];
}
if (!isNull(result.data)) {
List<PersonMiniSchedule> _schedule = scheduleMiniJsonToList(
result.data['person_max_score_per_schedule'],
);
return [
SliverToBoxAdapter(child: SizedBox(height: 30)),
_schedule.isEmpty
? SliverFillRemaining(
child: Center(
child: emptyList(context,
icon: FontAwesomeIcons.book, msg: "No Schedules Yet.")),
)
: SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return ScheduleCard(
schedule: _schedule[index],
);
}, childCount: _schedule.length)),
];
}
if (result.hasException) {
return [
ExceptionBuilder(
exception: result.exception,
hasData: isNull(result.data),
refetch: refetch)
];
}
return [
SliverToBoxAdapter(
child: SizedBox.shrink(),
)
];
}
here is the Query widget
Query(
options: QueryOptions(
variables: {'id': _appstate.token.hasuraId},
document: yourQuery()),
builder: (QueryResult result,
{VoidCallback refetch, FetchMore fetchMore}) {
return RefreshIndicator(
onRefresh: () async => refetch(),
child: CustomScrollView(
slivers: [
..._resolver(context, result, fetchMore, refetch),
SliverToBoxAdapter(
child: SizedBox(
height: 200,
)),
],
));
})
Upvotes: 1