Graphql Subscription not working for graphql_flutter

90 Views Asked by At

I am trying to use subscriptions in my app, when I add a user using mutation ,mysubscription is fired. When I try to add user using mutation from my flutter app , mysubscription of backend is fired but the subscription of my flutter app does not

I don't see any error in my app. Check video for more context

Here is my code

ValueNotifier<GraphQLClient> clientFor({
  required String uri,
  required String subscriptionUri,
}) {
  final HttpLink httpLink = HttpLink(
    uri,
  );

  final WebSocketLink websocketLink = WebSocketLink(
    subscriptionUri,
    config: const SocketClientConfig(
      autoReconnect: true,
      inactivityTimeout: Duration(seconds: 30),
    ),
    subProtocol: GraphQLProtocol.graphqlWs,
  );
  // authLink.concat(
  final Link link = httpLink.split(
      (request) => request.isSubscription, websocketLink, httpLink);

  return ValueNotifier<GraphQLClient>(
    GraphQLClient(
      cache: GraphQLCache(store: HiveStore()),
      link: link,
    ),
  );
}

/// Wraps the root application with the `graphql_flutter` client.
/// We use the cache for all state management.
class ClientProvider extends StatelessWidget {
  ClientProvider({
    super.key,
    @required this.child,
    required String uri,
    required String subscriptionUri,
  }) : client = clientFor(
          uri: uri,
          subscriptionUri: subscriptionUri,
        );

  final Widget? child;
  final ValueNotifier<GraphQLClient> client;

  @override
  Widget build(BuildContext context) {
    return GraphQLProvider(
      client: client,
      child: child,
    );
  }
}

I have wrapped MaterialApp with ClientProvider

return ClientProvider(
      subscriptionUri: "ws://localhost:4000/graphql",
      uri: "http://localhost:4000/graphql",
      child: MaterialApp(
        title: 'Flutter Demo',....

Then MyHomePage widget is as follows

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

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

class _MyHomePageState extends State<MyHomePage> {
  final TextEditingController _controller = TextEditingController();
  final List<String> items = [];

  String addUser = """
    mutation AddUser(\$input: AddUserInput!) {
    addUser(user: \$input) {
      name
      id
      
    }
  }
""";

 

  String mySubscription = """
  subscription mySubscription {
    newUser {
      name
    }
  }
""";

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
          child: Column(
        children: [
          TextField(
            controller: _controller,
            decoration: const InputDecoration(
              labelText: 'Enter your text',
            ),
          ),
          Mutation(
            options: MutationOptions(
              document: gql(addUser),
              update: (cache, result) {
                // debugPrint("Mutation Cache: ${cache.toString()}");
                // debugPrint("Mutation Result: ${result.toString()}");
              },
              onError: (error) {
                debugPrint("Mutation Error ${error}");
              },
              onCompleted: (resultData) {
                if (resultData != null) {
                  // context.showMessageDialog("${resultData['register']['firstName']}");

                  // debugPrint("Mutation data" + resultData.toString());
                }
              },
            ),
            builder: (runMutation, queryResult) {
              return TextButton(
                onPressed: () {
                  runMutation(<String, dynamic>{
                    "input": {
                      "name": _controller.text,
                      "likes": 3,
                      "movies": ["Star Wars"],
                      "isMale": true,
                      "money": 12.23
                    }
                  });
                },
                child: const Text("Submit User"),
              );
            },
          ),
        
          Subscription(
            options: SubscriptionOptions(
              document: gql(mySubscription),
            ),
            builder: ((QueryResult result) {
              if (result.hasException) {
                return Text("Error occured: " +
                    result.exception!.graphqlErrors[0].message);
              }

              if (result.isLoading) {
                return Center(
                  child: const CircularProgressIndicator(),
                );
              }

              debugPrint(result.data.toString());

              return ResultAccumulator.appendUniqueEntries(
                latest: result.data,
                builder: (context, {results}) => Text(results![0].toString()),
              );
            }),
          )
        ],
      )),
    );
  }
}

I tried using both Protocols GraphQLProtocol.graphqlWs & GraphQLProtocol.graphqlTransportWs but same issue.

My subscriptions work in react native with apollo client

Subscription should occur in flutter app as well when add user mutation occurs but it doesn't. Subscription does work on backend when I try to add a user from flutter app with mutation. I don't see any error in logs

1

There are 1 best solutions below

0
lilvagg On

The issue might be due to the lifecycle of your WebSocket connection. The connection might be closing before the subscription can receive any data.

One way to debug this is to add a keepAliveMessage to your SocketClientConfig. This will send a message to the server every inactivityTimeout to keep the connection alive.

If this doesn't solve your issue, it might be helpful to add more logging to your server to see when and why the WebSocket connection is closed.