Flutter Subscription Graphql: UnsupportedOperation, unknown not supported through the realtime channel

204 Views Asked by At

I am creating a subscription with GraphQL, and I need to consume that subscription with Flutter, I can connect to the ws and get the basic data, but seems my code still not working coz got the error, here's the error.

{"type":"error","payload":{"errors":[{"errorType":"UnsupportedOperation","message":"unknown not supported through the realtime channel"}]}}

I already googling the error, seems it's related auth error. But when I compare my flutter code with Postman setup, seems all already same setup.

Here's the Postman.

enter image description here

enter image description here

Here's the Message data from Postman.

{
  "id": "{{$randomUUID}}",
  "payload": {
    "data": "{\"query\":\"subscription updateCheckout { onUpdateCheckout(userId: \\\"{{userId}}\\\") { userId createdAt amount checkoutId maxAllowedAmount maxAvailableAmount message state trancheId }}\"}",
    "extensions": {
      "authorization": {
        "Authorization": "{{cognitoIdToken}}",
        "host": "{{apiHost}}"
      }
    }
  },
  "type": "start"
}

Here's my flutter code.

class AppSyncRequest extends RequestSerializer {
  final String uuid;
  final Map webSocketHeader;

  AppSyncRequest({
    required this.uuid,
    required this.webSocketHeader,
  });

  @override
  Map<String, dynamic> serializeRequest(Request request) {
    String query = printNode(request.operation.document);
    String data = jsonEncode({"query": query});
    final message = <String, dynamic>{
      "id": uuid,
      "payload": {
        "data": data,
        "extensions": {
          "authorization": webSocketHeader,
        }
      },
      "type": "start"
    };
    String str = jsonEncode(message);
    EpLogger.d('WebSocket Message Request: $str');
    return message;
  }
}

  void _onErrorSubscription(Object error, StackTrace stackTrace) {
    EpLogger.d('Listen Subscription Error: $error & $stackTrace');
  }

  void _onDoneSubscription() {
    EpLogger.d('Listen Subscription Done');
  }

  void _onErrorWebSocket(Object error, StackTrace stackTrace) {
    EpLogger.d('Listen WebSocket Error: $error & $stackTrace');
  }

  void _onDoneWebSocket() {
    EpLogger.d('Listen WebSocket Done');
  }

  @override
  Future<Map<String, dynamic>> subscription() async {
    try {
      var currentToken = "";
      final graphqlEndpoint = 'https://BASEURL/graphql/realtime';
      final subscriptionEndpoint =
          'wss://BASEURL/graphql/realtime?header=<EncodedHeader>&payload=e30=';
      const uuid = Uuid();
      final webSocketHeader = <String, dynamic>{
        "Authorization": currentToken,
        "host": ApiConstant.apiHost,
      };

      final HttpLink httpLink = HttpLink(
        graphqlEndpoint,
        defaultHeaders: {
          "Authorization": "Bearer $currentToken",
          'Sec-WebSocket-Protocol': "graphql-ws",
        },
      );

      final WebSocketLink webSocketLink = WebSocketLink(
        subscriptionEndpoint,
        config: SocketClientConfig(
          autoReconnect: true,
          serializer: AppSyncRequest(
            uuid: uuid.v1(),
            webSocketHeader: webSocketHeader,
          ),
          inactivityTimeout: const Duration(seconds: 60),
          connectFn: (url, protocol) {
            WebSocketChannel channel = WebSocketChannel.connect(
              url,
              protocols: protocol,
            );
            channel = channel.forGraphQL();
            channel.stream.listen(
              (data) {
                EpLogger.d('Listen WebSocket Active: $data');
              },
              onDone: _onDoneWebSocket,
              onError: _onErrorWebSocket,
              cancelOnError: true,
            );
            return channel;
          },
        ),
        subProtocol: ApiConstant.graphqlWs,
      );

      final AuthLink authLink =
          AuthLink(getToken: () => 'Bearer $currentToken');

      final Link linkSplitted = authLink.split(
        (request) => request.isSubscription,
        webSocketLink,
        httpLink,
      );

      final graphQLCache = GraphQLCache();

      final client = GraphQLClient(
        link: linkSplitted,
        cache: graphQLCache,
        defaultPolicies: DefaultPolicies(
          watchQuery: Policies(fetch: FetchPolicy.noCache),
          query: Policies(fetch: FetchPolicy.noCache),
          mutate: Policies(fetch: FetchPolicy.noCache),
          subscribe: Policies(fetch: FetchPolicy.noCache),
        ),
        alwaysRebroadcast: true,
      );

      const checkOutSubscription = r'''
subscription updateCheckout {
  onUpdateCheckout(userId: $userId) {
    userId
    createdAt
    amount
    checkoutId
    maxAllowedAmount
    maxAvailableAmount
    message
    state
    trancheId
  }
}
''';

      final options = SubscriptionOptions(
        document: gql(checkOutSubscription),
        variables: {
          "userId": "userId",
        },
      );

      final result = client.subscribe(options);
      Map<String, dynamic> data = {};
      result.listen(
        (event) {
          data = event.data ?? {};
          EpLogger.d('Listen Subscription: $event');
          EpLogger.d('Listen Subscription Data: $data');
        },
        onDone: _onDoneSubscription,
        onError: _onErrorSubscription,
        cancelOnError: true,
      );

      return Future.value(data);
    } on Exception {
      rethrow;
    }
  }
0

There are 0 best solutions below