flutter getx web sockets – stream data to be cascaded to provider and controller

Issue

Objective is simple

  • flutter app makes a call to graphql api over websockets
  • app view calls the controller, controller calls the provider, provider calls the AWS appsync api over websockets or over HTTP api socket call
  • we receive a stream of data from appsync api or HTTP api socket call over websockets every now and then from backend
  • streams need to be cascaded back to provider , and then to controller (this is the critical step)
  • controller (not the provider) would update the obs or reactive variable, make the UI reflect the changes

problem : data is recieved via websockets in the caller, but never passed back as stream to provider or controller to reflect the changes

sample code

actual caller
orderdata.dart

  @override
  Stream<dynamic> subscribe({
    String query,
    Map<String, dynamic> variables,
  }) async* {
    debugPrint('===->subscribe===');
    // it can be any stream here, http or file or image or media
    final Stream<GraphQLResponse<String>> operation = Amplify.API.subscribe(
      GraphQLRequest<String>(
        document: query,
        variables: variables,
      ),
      onEstablished: () {
        debugPrint(
          '===->subscribe onEstablished ===',
        );
      },
    );

    operation.listen(
      (event) async* {
        final jsonData = json.decode(event.data.toString());
        debugPrint('===->subscription data $jsonData');
        yield jsonData;
      },
      onError: (Object e) => debugPrint('Error in subscription stream: $e'),
    );
  }

in the provider
orderprovider.dart

  Stream<Order> orderSubscription(String placeId) async* {
    debugPrint('===->=== $placeId');
    subscriptionResponseStream = orderData.subscribe(
      query: subscribeToMenuOrder,
      variables: {"place_id": placeId},
    );

    subscriptionResponseStream.listen((event) async* {
      debugPrint(
        "===->=== yielded $event",
      );
      yield event;
    });
    debugPrint('===->=== finished');
  }

in the controller
homecontroller.dart

  Future<void> getSubscriptionData(String placeId) async {
    debugPrint('===HomeController->getSubscriptionData===');
    OrderProvider().orderSubscription(placeId).listen(
          (data) {
            //this block is executed when data event is receivedby listener
            debugPrint('Data: $data');
            Get.snackbar('orderSubscription', data.toString());
          },
          onError: (err) {
            //this block is executed when error event is received by listener
            debugPrint('Error: $err');
          },
          cancelOnError:
              false, //this decides if subscription is cancelled on error or not
          onDone: () {
            //this block is executed when done event is received by listener
            debugPrint('Done!');
          },
        );
  }

homeview calls homecontroller

Solution

Try using map for transforming Streams:

 @override
  Stream<dynamic> subscribe({
    String query,
    Map<String, dynamic> variables,
  }) {
    debugPrint('===->subscribe===');
    // it can be any stream here, http or file or image or media
    final Stream<GraphQLResponse<String>> operation = Amplify.API.subscribe(
      GraphQLRequest<String>(
        document: query,
        variables: variables,
      ),
      onEstablished: () {
        debugPrint(
          '===->subscribe onEstablished ===',
        );
      },
    );
    
    return operation.map((event) {
      return json.decode(event.data);
    });
  }

  // elsewhere

  final subscription = subscribe(
    query: 'some query', 
    variables: {},
  );

  subscription.listen(
    (jsonData) {
      debugPrint('===->subscription data $jsonData');
    },
    onError: (Object e) => debugPrint('Error in subscription stream: $e'),
  );

Answered By – Dillon Nys

Answer Checked By – Clifford M. (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *