Flutter GraphQL服务端交互插件graphql_server的使用

Flutter GraphQL服务端交互插件graphql_server的使用


简介

graphql_server 是一个用于实现 GraphQL 服务器的基础包。它不依赖任何特定框架,因此可以在任何 Dart 项目中使用。

特点

  • 提供 GraphQL 类来处理查询。
  • 支持订阅(Subscriptions)。
  • 自动处理模式的反射(Introspection)。
  • 可选支持 dart:mirrors 以简化字段解析。

安装

pubspec.yaml 文件中添加以下依赖:

dependencies:
  graphql_server: ^x.x.x

然后运行 flutter pub get


基本用法

1. 查询功能

GraphQL 类的核心方法是 parseAndExecute,它可以解析并执行 GraphQL 查询。

示例代码

import 'package:graphql_schema/graphql_schema.dart';
import 'package:graphql_server/graphql_server.dart';
import 'package:test/test.dart';

void main() {
  test('single element', () async {
    // 定义一个 Todo 类型
    var todoType = objectType('todo', fields: [
      field(
        'text',
        graphQLString,
        resolve: (obj, args) => obj.text,
      ),
      field(
        'completed',
        graphQLBoolean,
        resolve: (obj, args) => obj.completed,
      ),
    ]);

    // 定义 Schema
    var schema = graphQLSchema(
      queryType: objectType('api', fields: [
        field(
          'todos',
          listOf(todoType),
          resolve: (_, __) => [
            Todo(
              text: 'Clean your room!',
              completed: false,
            )
          ],
        ),
      ]),
    );

    // 创建 GraphQL 实例
    var graphql = GraphQL(schema);

    // 执行查询
    var result = await graphql.parseAndExecute('{ todos { text } }');

    // 输出结果
    print(result);
    expect(result, {
      'todos': [
        {'text': 'Clean your room!'}
      ]
    });
  });
}

// 定义 Todo 类
class Todo {
  final String text;
  final bool completed;

  Todo({this.text, this.completed});
}

解释

  1. objectType 定义了一个 Todo 类型,包含两个字段:textcompleted
  2. schema 定义了查询类型 api,其中包含一个 todos 字段,返回的是 Todo 列表。
  3. parseAndExecute 方法执行了 GraphQL 查询 { todos { text } },并返回结果。

订阅功能

GraphQL 的订阅功能允许客户端监听实时数据更新。graphql_server 提供了基于 package:stream_channel 的实现。

示例代码
import 'package:graphql_schema/graphql_schema.dart';
import 'package:graphql_server/graphql_server.dart';
import 'package:stream_channel/stream_channel.dart';
import 'package:test/test.dart';

void main() {
  test('subscription', () async {
    // 定义 Todo 类型
    var todoType = objectType('todo', fields: [
      field(
        'text',
        graphQLString,
        resolve: (obj, args) => obj.text,
      ),
      field(
        'completed',
        graphQLBoolean,
        resolve: (obj, args) => obj.completed,
      ),
    ]);

    // 定义 Subscription 类型
    var subscriptionType = objectType('subscription', fields: [
      field(
        'onTodo',
        todoType,
        resolve: (_, __) {
          return Stream.fromIterable([
            Todo(text: 'Task 1', completed: false),
            Todo(text: 'Task 2', completed: true),
          ]);
        },
      ),
    ]);

    // 定义 Schema
    var schema = graphQLSchema(
      subscriptionType: subscriptionType,
    );

    // 创建 GraphQL 实例
    var graphql = GraphQL(schema);

    // 模拟 WebSocket 连接
    var channel = StreamChannelController().server;
    var client = stw.RemoteClient(channel.stream.cast<String>());
    var server = _GraphQLWSServer(client, graphql, null, null, 0);
    await server.done;

    // 执行订阅查询
    var subscriptionResult = await graphql.parseAndExecute('subscription { onTodo { text completed } }');
    print(subscriptionResult);
    expect(subscriptionResult, [
      {'onTodo': {'text': 'Task 1', 'completed': false}},
      {'onTodo': {'text': 'Task 2', 'completed': true}},
    ]);
  });
}

解释

  1. subscriptionType 定义了一个 onTodo 字段,返回的是 Todo 对象的流。
  2. _GraphQLWSServer 处理 WebSocket 连接,并将订阅事件传递给客户端。
  3. parseAndExecute 方法执行订阅查询,返回实时更新的数据。

Introspection

Introspection 允许客户端查询服务器的模式信息。GraphQL 类会自动处理这一点,无需额外编写代码。

如果需要手动反射模式,可以使用 reflectSchema 方法。

示例代码

import 'package:graphql_schema/graphql_schema.dart';
import 'package:graphql_server/graphql_server.dart';

void main() {
  var schema = graphQLSchema(
    queryType: objectType('Query', fields: [
      field('hello', graphQLString, resolve: (_, __) => 'Hello World'),
    ]),
  );

  var introspectionResult = GraphQL.reflectSchema(schema);
  print(introspectionResult);
}

解释

  1. reflectSchema 方法返回一个 JSON 表示的模式信息。
  2. 这对于调试或生成客户端代码非常有用。

使用 dart:mirrors 简化字段解析

默认情况下,dart:mirrors 不是必需的,但可以选择启用以简化字段解析。

示例代码

import 'package:graphql_server/graphql_server.dart';

void main() {
  var schema = graphQLSchema(
    queryType: objectType('Query', fields: [
      field(
        'user',
        userType,
        resolve: mirrorsFieldResolver, // 使用 mirrorsFieldResolver
      ),
    ]),
  );

  var graphql = GraphQL(schema);
  var result = graphql.parseAndExecute('{ user { name age } }');
  print(result);
}

更多关于Flutter GraphQL服务端交互插件graphql_server的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter GraphQL服务端交互插件graphql_server的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,graphql_server 是一个用于与GraphQL服务端进行交互的插件。它允许你在Flutter应用中执行GraphQL查询、变更和订阅操作。以下是如何使用 graphql_server 插件的基本步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 graphql_server 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  graphql_server: ^2.0.0

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

2. 创建GraphQL客户端

接下来,你需要创建一个GraphQL客户端来与服务端进行交互。通常,你需要指定GraphQL服务端的URL。

import 'package:graphql_server/graphql_server.dart';

final GraphQLClient client = GraphQLClient(
  link: HttpLink('https://your-graphql-endpoint.com/graphql'),
  cache: GraphQLCache(),
);

3. 执行查询

你可以使用 client.query 方法来执行GraphQL查询。以下是一个简单的查询示例:

import 'package:graphql_server/graphql_server.dart';

Future<void> fetchData() async {
  const String query = '''
    query {
      users {
        id
        name
        email
      }
    }
  ''';

  final QueryOptions options = QueryOptions(
    document: gql(query),
  );

  final QueryResult result = await client.query(options);

  if (result.hasException) {
    print('Error: ${result.exception}');
  } else {
    print('Data: ${result.data}');
  }
}

4. 执行变更

你可以使用 client.mutate 方法来执行GraphQL变更操作。以下是一个简单的变更示例:

import 'package:graphql_server/graphql_server.dart';

Future<void> createUser(String name, String email) async {
  const String mutation = '''
    mutation CreateUser(\$name: String!, \$email: String!) {
      createUser(name: \$name, email: \$email) {
        id
        name
        email
      }
    }
  ''';

  final MutationOptions options = MutationOptions(
    document: gql(mutation),
    variables: <String, dynamic>{
      'name': name,
      'email': email,
    },
  );

  final QueryResult result = await client.mutate(options);

  if (result.hasException) {
    print('Error: ${result.exception}');
  } else {
    print('Data: ${result.data}');
  }
}

5. 处理订阅

graphql_server 也支持GraphQL订阅。你可以使用 client.subscribe 方法来订阅实时数据。

import 'package:graphql_server/graphql_server.dart';

Stream<QueryResult> subscribeToMessages() {
  const String subscription = '''
    subscription {
      messageAdded {
        id
        content
      }
    }
  ''';

  final SubscriptionOptions options = SubscriptionOptions(
    document: gql(subscription),
  );

  return client.subscribe(options);
}

6. 处理错误

在执行查询、变更或订阅时,可能会遇到错误。你可以通过检查 QueryResulthasException 属性来处理错误。

if (result.hasException) {
  print('Error: ${result.exception}');
} else {
  print('Data: ${result.data}');
}

7. 使用缓存

graphql_server 提供了缓存机制,你可以通过 GraphQLCache 来管理缓存。默认情况下,查询结果会被缓存,你可以通过 fetchPolicy 来控制缓存行为。

final QueryOptions options = QueryOptions(
  document: gql(query),
  fetchPolicy: FetchPolicy.networkOnly, // 忽略缓存,直接从网络获取
);

8. 使用链接中间件

graphql_server 支持链接中间件,你可以在请求链中添加自定义逻辑。例如,你可以添加一个认证中间件来在每个请求中添加认证头。

import 'package:graphql_server/graphql_server.dart';

final AuthLink authLink = AuthLink(
  getToken: () async => 'Bearer your-auth-token',
);

final Link link = authLink.concat(HttpLink('https://your-graphql-endpoint.com/graphql'));

final GraphQLClient client = GraphQLClient(
  link: link,
  cache: GraphQLCache(),
);

9. 使用Fragment

GraphQL片段(Fragment)可以帮助你重用查询逻辑。你可以在查询中使用片段来减少重复代码。

const String userFragment = '''
  fragment UserFields on User {
    id
    name
    email
  }
''';

const String query = '''
  $userFragment
  query {
    users {
      ...UserFields
    }
  }
''';

10. 使用变量

GraphQL查询和变更可以接受变量。你可以通过 variables 参数传递变量。

final QueryOptions options = QueryOptions(
  document: gql(query),
  variables: <String, dynamic>{
    'userId': 123,
  },
);
回到顶部