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 620 forks source link

Flutter 3.0.2 / graphql_flutter: 5.1.1-beta.3 | Subscription QueryResult returns null #1162

Closed hamzablx195 closed 2 years ago

hamzablx195 commented 2 years ago

The definition for the GraphQL Client is integrated into the code. Just trying to hook up the Subscription widget as provided by graphQL flutter.

The Query and Mutations work fine with the graphql endpoint. This is a public endpoint. We don't have any authorisation headers.

With the Subscription operation, the value being returned is always null and it is not listening to any updates.

Package version: graphql_flutter: ^5.1.1-beta.3

To Reproduce Sample Main file::

import 'package:flutter/material.dart';
      import 'package:graphql_flutter/graphql_flutter.dart';

      void main() async {
        await initHiveForFlutter();
        // Hive.
        runApp(const MyApp());
      }

      class MyApp extends StatefulWidget {
        const MyApp({Key? key}) : super(key: key);

        @override
        State<MyApp> createState() => _MyAppState();
      }

      class _MyAppState extends State<MyApp> {
        ValueNotifier<GraphQLClient>? gqlClient;

        @override
        void initState() {
          // TODO: implement initState
          super.initState();
          gqlClient = ValueNotifier(
            initializeGQL(),
          );
        }

        @override
        Widget build(BuildContext context) {
          // initializeGQL();

          return GraphQLProvider(
            client: gqlClient,
            child: MaterialApp(
              title: 'Flutter Demo',
              theme: ThemeData(
                primarySwatch: Colors.blue,
              ),
              home: const MyHomePage(
                title: 'Flutter Demo Home Page',
              ),
            ),
          );
        }

        GraphQLClient initializeGQL() {
          String apiLink = 'https://idh66.sse.codesandbox.io/graphql';
          String wssLink = 'wss://idh66.sse.codesandbox.io/graphql';
          HttpLink link = HttpLink(apiLink);

          var wsLink = WebSocketLink(
            wssLink,
            config: const SocketClientConfig(
              inactivityTimeout: Duration(seconds: 5),
            ),
            subProtocol: SocketSubProtocol.graphqlWs,
          );
          final Link linkSplitted = link.split(
            (request) => request.isSubscription,
            wsLink,
            link,
          );
          Policies pp = Policies(
            fetch: FetchPolicy.networkOnly,
            error: ErrorPolicy.all,
            cacheReread: CacheRereadPolicy.mergeOptimistic,
          );
          print('''

          -------------------------------------------------------------------------------

          ''');
          print(linkSplitted);
          return GraphQLClient(
            link: linkSplitted,
            cache: GraphQLCache(store: HiveStore()),
            alwaysRebroadcast: true,
            defaultPolicies: DefaultPolicies(
              subscribe: pp,
              query: pp,
              mutate: pp,
            ),
          );
        }
      }

      class MyHomePage extends StatefulWidget {
        const MyHomePage({Key? key, required this.title}) : super(key: key);

        final String title;

        @override
        State<MyHomePage> createState() => _MyHomePageState();
      }

      class _MyHomePageState extends State<MyHomePage> {
        SubscriptionOptions? ops;

        final String readNumber = """
        query Query {
        currentNumber
      }
      """;

        final subscriptionDocument = gql('''
      subscription Subscription {
        numberIncremented
      }''');
        @override
        void initState() {
          super.initState();

          setSubscription();
        }

        setSubscription() {
          ops = SubscriptionOptions(
            fetchPolicy: FetchPolicy.networkOnly,
            errorPolicy: ErrorPolicy.all,
            document: subscriptionDocument,
          );
        }

        @override
        Widget build(BuildContext context) {
          return Scaffold(
            appBar: AppBar(
              title: Text(widget.title),
            ),
            body: Subscription(
                options: ops!,
                builder: (snap) {
                  return Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      const Text('hello from subscription'),
                      Text('Subscription Data: == ${snap.data.toString()}'),
                      Query(
                        options: QueryOptions(
                          document: gql(
                            readNumber,
                          ), // this is the query string you just created

                          pollInterval: const Duration(seconds: 10),
                        ),
                        // Just like in apollo refetch() could be used to manually trigger a refetch
                        // while fetchMore() can be used for pagination purpose
                        builder: (QueryResult result,
                            {VoidCallback? refetch, FetchMore? fetchMore}) {
                          if (result.hasException) {
                            return Text(result.exception.toString());
                          }

                          if (result.isLoading) {
                            return const Text('Loading');
                          }

                          return Text(result.data.toString());
                        },
                      ),
                    ],
                  );
                }),
          );
        }
      }

The Subscription operation keeps returning null value.

Expected behavior A listener to work properly as it does with the exposed apollo client on the server.

device / execution context Tested on Android physical and emulated devices.

Other useful/optional fields

Please fill or delete these sections if you don't fill them in

Query Result Response as received by the subscription.

Stacktrace: ```dart { QueryResult(source: QueryResultSource.network, data: {numberIncremented: null}, context: Context({ResponseExtensions: Instance of 'ResponseExtensions', HttpLinkResponseContext: Instance of 'HttpLinkResponseContext'}), exception: null, timestamp: 2022-06-16 02:27:51.565108)} ```
vincenzopalazzo commented 2 years ago

This is the reason of your null value Selection_047

aiyajsupra commented 2 years ago

facing same issue!!!!

dhruvinwebelight commented 2 years ago

@vincenzopalazzo facing same issue with WebSocketLink Screenshot 2022-06-17 at 8 47 58 PM

vincenzopalazzo commented 2 years ago

@dhruvinwebelight @hamzablx195 can you please try your code with subProtocol: SocketSubProtocol.graphqlWs there is a collision name here

This is the reason https://github.com/zino-hofmann/graphql-flutter/pull/1180

hamzablx195 commented 2 years ago

Hey @vincenzopalazzo , tried SocketSubProtocol.graphqlWs. Still it wont work and keeps returning null on the subscription result.

vincenzopalazzo commented 2 years ago

Sorry I made a typo, I mean if you want try with SocketSubProtocol.graphqlTransportWs that is the new protocol, I get the correct data back, on my demo that I'm preparing for integration testing

hamzablx195 commented 2 years ago

Still no luck. It keeps returning the same result. I went through these protocols earlier as well. Can you please share the example that you're using?

vincenzopalazzo commented 2 years ago

Sure this is the example: https://github.com/zino-hofmann/graphql-flutter/tree/macros/chat_example/packages/graphql_flutter/example/graphql_chat

And this is the Apollo Server https://github.com/vincenzopalazzo/keep-safe-graphql

This needs to investigate but please fix your example because it is completely normal that you have null in the data if you are using the wrong protocol

vincenzopalazzo commented 2 years ago

Keeping alive for a bit

hamzablx195 commented 2 years ago

Sure this is the example: https://github.com/zino-hofmann/graphql-flutter/tree/macros/chat_example/packages/graphql_flutter/example/graphql_chat

And this is the Apollo Server https://github.com/vincenzopalazzo/keep-safe-graphql

This needs to investigate but please fix your example because it is completely normal that you have null in the data if you are using the wrong protocol

I tried the graphql_chat repo you shared. The subscription still don't work. New updates on the subscription are not received in both, the graphql implementation & the flutter_graphql implementation.

When configured, the first read is successful now, it gets the latest value once. But if I trigger mutations on the apollo-server attached, I don't receive any updates on this subscription.

vincenzopalazzo commented 2 years ago

I tried the graphql_chat repo you shared. The subscription still don't work. New updates on the subscription are not received in both, the graphql implementation & the flutter_graphql implementation. When configured, the first read is successful now, it gets the latest value once. But if I trigger mutations on the apollo-server attached, I don't receive any updates on this subscription.

Can you reach me on discord? we can try track this!

vincenzopalazzo commented 2 years ago

I found the bug, is how you create the link!

Please use the static method provided by the Link Library

  final Link link = Link.split(
    (request) => request.isSubscription,
    wsLink,
    httpLink,
  );
hamzablx195 commented 2 years ago

Perfect, yes that was it. Thank you so much for your time and effort!!

vincenzopalazzo commented 2 years ago

Lovely!

BS-Wissem commented 1 year ago

Hello, I used your code and the subscription is still returning null, but I noticed a successive disconnection after using

final Link link = Link.split(
    (request) => request.isSubscription,
    wsLink,
    httpLink,
  ); 

Console log:

Initialising connection
Disconnected from websocket.

I am using graphql_flutter: 5.1.2 Any hints? Thank you.

malik19995 commented 1 year ago

Hello @BS-Wissem,

Please use the latest beta version of the plugin available, and update the subProtocol in SocketConfig:

instead of subProtocol: SocketSubProtocol.graphqlWs, add subProtocol: GraphQLProtocol.graphqlTransportWs,

This should resolve the issue. Hope this works for you as well.

BS-Wissem commented 1 year ago

Hello @malik19995 , Thanks so much it worked for version 5.1.2 and 5.1.1-beta.5.