interceptor for graphql in flutter for handling error

Viewed 1643

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.

2 Answers

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,
                      )),
                    ],
                  ));
            })

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.

Related