zino-hofmann / graphql-flutter

A GraphQL client for Flutter, bringing all the features from a modern GraphQL client to one easy to use package.
https://zino-hofmann.github.io/graphql-flutter
MIT License
3.25k stars 622 forks source link

retry request when token invalid or expired occured #1373

Open J-Rigondo opened 1 year ago

J-Rigondo commented 1 year ago

``Hello ! when user send request, access token expired, server will response error, my GraphqlClient's ErrorLink catch onGraphQLError, on this handler do that get new access token and change only request header, and retry request. but forward method not working. I use graphql_codgen, so I don't want use dio. I think get refresh token in AuthLink bad. server have token validation role. How to implement this use your library?

class ApiService {
  late final GraphQLClient _client;

  ApiService() {
    final authLink = AuthLink(getToken: _getToken);
    final httpLink = HttpLink(Platform.isAndroid
        ? 'http://10.0.2.2:4000/graphql'
        : 'http://localhost:4000/graphql');
    final errorLink = ErrorLink(
      onGraphQLError: (request, forward, response) {
        print('=====================in Error link===========================');
        print(request.context);

        if (counter < 1) {
          final newReq = request.updateContextEntry<HttpLinkHeaders>((headers) {
            print(headers?.headers);
            return HttpLinkHeaders(headers: <String, String>{
              ...headers?.headers ?? <String, String>{},
              'Authorization': 'Bearer refresh new',
            });
          });
          counter++;
          print('forward req');
          forward(newReq);
        }

        print(counter);

        print('=====================in Error link===========================');

        // final oldHeaders = response.context.entry();
        //
        // print(oldHeaders);
        //
      },
    );

    final link = Link.from([authLink, errorLink, httpLink]);

    _client = GraphQLClient(
      link: link,
      cache: GraphQLCache(),
      defaultPolicies: DefaultPolicies(
        query: Policies(fetch: FetchPolicy.networkOnly),
      ),
    );
  }

  Future<String?> _getToken() async {
    return 'Bearer raewfawefawfwalfekjf';
  }

  Future<void> gqlRequest() async {
    final result = await _client.query$Relays_cursor_list(
        Options$Query$Relays_cursor_list(
            variables: Variables$Query$Relays_cursor_list(
                orderBy: Enum$order_by.POPULARITY, take: 5)));

    if (result.hasException) {
      // print(result.exception.toString());
    }
    // print(result.parsedData?.relays_cursor_list.toString());
    return;
  }
}
Sh1d0w commented 1 year ago

The order of the links matters change your code to:

 final Link link = errorLink.concat(authLink.concat(httpLink));

and it will work.

PS. Also onGraphQLError expects stream of response type so you should change the function to

onGraphQLError: (request, forward, response) async* {
...
}

And return the forward like this:

yield* forward(newReq);