Flutter WebSocket GraphQL通信插件gql_websocket_link的使用

发布于 1周前 作者 wuwangju 来自 Flutter

Flutter WebSocket GraphQL通信插件gql_websocket_link的使用

介绍

gql_websocket_link 是一个用于在 Flutter 应用中通过 WebSocket 与 GraphQL 后端进行通信的插件。它支持订阅(subscriptions)、查询(queries)和变更(mutations)。该插件支持两种 WebSocket 子协议:graphql-wsgraphql-transport-ws,分别通过 WebSocketLinkTransportWebSocketLink 类实现。

主要特性

  • 自动重连:支持 autoReconnect,在连接断开后会自动重新订阅。
  • 协议支持:支持 graphql-wsgraphql-transport-ws 协议。
  • 灵活配置:可以根据需要选择不同的 WebSocket 实现方式。

使用方法

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 gql_websocket_linkgql_link 依赖:

dependencies:
  gql_websocket_link: ^0.4.0
  gql_link: ^0.4.0

然后运行 flutter pub get 来安装依赖。

2. 使用 WebSocketLink / graphql-ws 协议
import 'package:gql_link/gql_link.dart';
import 'package:gql_websocket_link/gql_websocket_link.dart';

void main() {
  // 创建 WebSocketLink 实例,指定 GraphQL 服务器的 WebSocket 端点
  final link = Link.from([
    WebSocketLink("ws://<GRAPHQL_SERVER_ENDPOINT>/graphql"),
  ]);

  // 使用 link 进行 GraphQL 操作
  // 例如,执行查询、变更或订阅
}
3. 使用 TransportWebSocketLink / graphql-transport-ws 协议
import 'package:gql_link/gql_link.dart';
import 'package:gql_websocket_link/gql_websocket_link.dart';

void main() {
  // 创建 TransportWebSocketLink 实例,指定 WebSocketMaker
  final link = Link.from([
    TransportWebSocketLink(
      TransportWsClientOptions(
        socketMaker: WebSocketMaker.url(() => "ws://<GRAPHQL_SERVER_ENDPOINT>/graphql"),
      ),
    ),
  ]);

  // 使用 link 进行 GraphQL 操作
  // 例如,执行查询、变更或订阅
}

完整示例 Demo

以下是一个完整的示例,展示了如何使用 gql_websocket_link 进行 WebSocket GraphQL 订阅、查询和变更操作。假设我们有一个 GraphQL 服务器运行在 ws://localhost:5000/graphql,并且我们想要订阅某个事件、查询数据并执行变更。

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await initHiveForFlutter();

  final HttpLink httpLink = HttpLink('http://localhost:5000/graphql');
  final WebSocketLink webSocketLink = WebSocketLink(
    'ws://localhost:5000/graphql',
    config: SocketClientConfig(
      autoReconnect: true,
      inactivityTimeout: const Duration(seconds: 30),
    ),
  );

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

  runApp(
    GraphQLProvider(
      client: ValueNotifier<GraphQLClient>(
        GraphQLClient(
          link: link,
          cache: GraphQLCache(store: HiveStore()),
        ),
      ),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter GraphQL WebSocket Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  [@override](/user/override)
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter GraphQL WebSocket Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            Query(
              options: QueryOptions(
                document: gql(r'''
                  query GetItems {
                    items {
                      id
                      name
                    }
                  }
                '''),
              ),
              builder: (QueryResult result, {VoidCallback? refetch, FetchMore? fetchMore}) {
                if (result.hasException) {
                  return Text(result.exception.toString());
                }

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

                final items = result.data?['items'] as List<dynamic>?;

                return ListView.builder(
                  shrinkWrap: true,
                  itemCount: items?.length ?? 0,
                  itemBuilder: (context, index) {
                    final item = items?[index];
                    return ListTile(
                      title: Text(item?['name']),
                    );
                  },
                );
              },
            ),
            Subscription(
              options: SubscriptionOptions(
                document: gql(r'''
                  subscription OnNewItemAdded {
                    newItemAdded {
                      id
                      name
                    }
                  }
                '''),
              ),
              builder: (QueryResult result, {VoidCallback? refetch, FetchMore? fetchMore}) {
                if (result.hasException) {
                  return Text(result.exception.toString());
                }

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

                final newItem = result.data?['newItemAdded'];

                if (newItem != null) {
                  return ListTile(
                    title: Text('New Item Added: ${newItem['name']}'),
                  );
                }

                return Container();
              },
            ),
            ElevatedButton(
              onPressed: () {
                final MutationOptions options = MutationOptions(
                  document: gql(r'''
                    mutation AddItem($name: String!) {
                      addItem(name: $name) {
                        id
                        name
                      }
                    }
                  '''),
                  variables: {'name': 'New Item'},
                );

                final GraphQLClient client = GraphQLProvider.of(context).value;
                client.mutate(options).then((result) {
                  if (result.hasException) {
                    print(result.exception.toString());
                  } else {
                    print('Item added: ${result.data?['addItem']['name']}');
                  }
                });
              },
              child: Text('Add New Item'),
            ),
          ],
        ),
      ),
    );
  }
}

更多关于Flutter WebSocket GraphQL通信插件gql_websocket_link的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter WebSocket GraphQL通信插件gql_websocket_link的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用gql_websocket_link插件来实现WebSocket GraphQL通信的示例代码。这个示例将展示如何配置GraphQL客户端以使用WebSocket进行订阅操作。

首先,确保你已经在pubspec.yaml文件中添加了必要的依赖项:

dependencies:
  flutter:
    sdk: flutter
  graphql_flutter: ^5.0.0 # 或者最新版本
  gql: ^0.13.0 # 或者最新版本
  gql_exec: ^0.3.0 # 或者最新版本
  gql_websocket_link: ^0.3.0 # 或者最新版本

然后,运行flutter pub get来安装这些依赖项。

接下来,在你的Flutter项目中,按照以下步骤配置和使用gql_websocket_link

  1. 定义GraphQL订阅查询
import 'package:gql/ast.dart';

const String subscriptionQuery = r'''
  subscription OnMessageUpdate {
    messageUpdated {
      id
      content
    }
  }
''';

final DocumentNode subscriptionDocument = parseString(subscriptionQuery);
  1. 创建WebSocket链接
import 'package:gql/link.dart';
import 'package:gql_websocket_link/gql_websocket_link.dart';

// 替换为你的GraphQL服务器WebSocket端点
final String websocketUrl = 'wss://your-graphql-endpoint/subscriptions';

// 创建WebSocket链接
final WebSocketLink webSocketLink = WebSocketLink(
  url: websocketUrl,
  config: WebSocketLinkConfig(
    // 如果需要认证头,可以在这里添加
    headers: () async => {
      'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    },
  ),
);
  1. 创建GraphQL客户端
import 'package:graphql_flutter/graphql_flutter.dart';

// 使用WebSocket链接创建ValueNotifierLink(可选,用于缓存)
final ValueNotifier<GraphQLClient> client = ValueNotifier(
  GraphQLClient(
    link: webSocketLink,
    cache: GraphQLCache(),
  ),
);
  1. 在Flutter组件中使用订阅
import 'package:flutter/material.dart';
import 'package:graphql_flutter/graphql_flutter.dart';

class SubscriptionScreen extends StatefulWidget {
  @override
  _SubscriptionScreenState createState() => _SubscriptionScreenState();
}

class _SubscriptionScreenState extends State<SubscriptionScreen> {
  final StreamController<Map<String, dynamic>> _controller = StreamController();

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('GraphQL WebSocket Subscription')),
      body: StreamBuilder<Object?>(
        stream: _controller.stream,
        builder: (context, snapshot) {
          if (snapshot.hasError) {
            return Text('Error: ${snapshot.error}');
          }

          if (snapshot.hasData) {
            final data = snapshot.data as Map<String, dynamic>;
            return ListView.builder(
              itemCount: data['messageUpdated']?.length ?? 0,
              itemBuilder: (context, index) {
                final message = data['messageUpdated']![index];
                return ListTile(
                  title: Text('ID: ${message['id']}, Content: ${message['content']}'),
                );
              },
            );
          }

          return Center(child: CircularProgressIndicator());
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 发起订阅
          client.value.subscribe(
            subscriptionDocument,
            rootValue: () => _controller.sink,
          );
        },
        tooltip: 'Start Subscription',
        child: Icon(Icons.play_arrow),
      ),
    );
  }
}

注意:上面的示例代码中的rootValue部分需要根据你的实际需求进行调整,因为gql_websocket_link的API可能会要求你提供一个处理订阅响应的方式。在这个例子中,我们直接将数据发送到_controller.sink,但你可能需要根据你的业务逻辑进行调整。

另外,上面的代码假设你已经有一个正在运行的GraphQL服务器,并且该服务器支持WebSocket订阅。如果服务器需要认证,请确保在WebSocketLinkConfigheaders中提供了正确的认证信息。

请根据你的具体需求和环境调整上述代码。希望这个示例能帮助你理解如何在Flutter项目中使用gql_websocket_link插件进行WebSocket GraphQL通信。

回到顶部