GraphQL 代码生成

这是一个关于将 GraphQL 代码生成为 Dart/Flutter 的有见地的工具。

它将允许您用最少的配置生成 Dart 序列化器和客户端助手。
该框架不对您的片段或查询的结构做出任何假设,
对于每个 operation.graphql,框架将生成一个 operation.graphq.dart 文件
其中包含 Dart 类。

有关该工具和动机的更多信息,请参阅 GraphQL 代码生成深入分析
以及如何使用该工具构建您的 Flutter 应用,请参阅 构建您的 Flutter GraphQL 应用

构建器依赖于 json_serializable 来生成实际的序列化器,
因此,除了上面提到的两个文件之外,它还将生成一个 operation.graphql.g.dart
文件。

该框架不会为您获取您的 schema,因此在运行此命令之前,您需要
将您的 schema 添加到您的项目中。

安装

graphql_codegen: <current_version> 添加到您的 dev_dependencies

该项目依赖于 json_serializable,因此请在此处了解如何设置 此处
它也是一个构建器,因此您需要设置 build_runner。在此处了解更多 此处

基本用法

要从 GraphQL schema 生成 Dart 类,首先需要创建一个 schema.graphql 文件和 GraphQL 文档文件。

例如

给定 schema

# schema.graphql

type Query {
  fetch_person(id: ID!): Person
}

type Person {
  full_name: String!
  nickname: String
  website: URL
  date_of_birth: ISODateTime
  parents: [Person!]
  siblings: [Person!]
  children: [Person!]
}

scalar ISODateTime

scalar URL

和一个查询

# person.graphql

query FetchPerson($id: ID!) {
  fetch_person(id: $id) {
    name: full_name
  }
}

然后您可以使用以下命令生成 Dart 类

$ dart run build_runner build

之后,您可以使用以下方法解析结果

// person.dart

import 'person.graphql.dart';

main () {
    final data = fetchDataFromSomewhereMaybeOuterSpace();
    final parsedData = QueryFetchPerson.fromJson(data);
    final name = parsedData.fetchPerson?.name;
    print(name);
}

使用片段

片段是重用应用中查询的绝佳工具。它们用于创建“接口”
这使得您可以轻松地在应用中解析数据。给定上面的 schema 和查询

# parents_and_children.graphql

fragment PersonSummary on Person {
  full_name
}

query FetchParentsAndChildren {
  fetch_person(id: "1") {
    parents {
      ...PersonSummary
      nickname
    }

    children {
      ...PersonSummary
    }
  }
}

这将允许您执行以下操作

// parents_and_children.dart

import 'parents_and_children.graphql.dart';

printPerson(FragmentPersonSummary person) {
    print(person.fullName);
}

main () {
    final data = fetchDataFromTheVoid();
    final parsedData = QueryFetchParentsAndChildren.fromJson(data);
    for (final parent in parsedData?.fetchPerson.parents ?? []) {
        printPerson(parent);
        print(parent.dob);
    }
    for (final child in parsedData?.fetchPerson.children ?? []) {
        printPerson(child);
    }
}

FragmentPersonSummary 是一个抽象类,其形状为

...
abstract class FragmentPersonSummary {
    String get fullName;
}
...

并将在生成的 .graphql.dart 文件中可用,用于包含片段的 .graphql 文件
包含片段。

自定义标量

开箱即用,标准片段都受支持并映射到相关的 Dart 类型。您可以添加
新映射用于自定义标量或覆盖现有配置。

在上面的 schema 中,您可以看到我们定义了 ISODateTime 标量。在此示例中,它包含
一个带有 iso 格式日期时间字符串的字符串。我们希望通过以下方式将其映射到 Dart 的 DateTime 类型
将以下配置添加到 build.yaml 文件中

# build.yaml

targets:
  $default:
    builders:
      graphql_codegen:
        options:
          scalars:
            ISODateTime:
              type: DateTime
            JSON:
              type: Map<String, dynamic>

由于 json_serializable 支持从字符串解析 DateTime,因此这就是我们所需要做的。

假设我们想使用自定义日期时间类(例如 CustomDateTime),我们可以添加

# build.yaml

targets:
  $default:
    builders:
      graphql_codegen:
        options:
          scalars:
            ISODateTime:
              type: CustomDateTime
              fromJsonFunctionName: customDateTimeFromJson
              toJsonFunctionName: customDateTimeToJson
              import: package:my_app/scalar.dart

并创建一个 scalar.dart 文件,其中包含您的转换器函数和类。

// custom_date_time.dart
class CustomDateTime {
    final String datetime;

    CustomDateTime(this.datetime);
}

and

// scalar.dart

export 'custom_date_time.dart' show {CustomDateTime};

CustomDateTime customDateTimeFromJson(dynamic data) => CustomDateTime(data as String);
dynamic customDateTimeToJson(CustomDateTime time) => time.datetime;

现在所有使用 ISODateTime 的字段都将是 CustomDateTime 实例。

客户端

解析数据很好,但实际上并不十分实用。因此,我们可以生成
客户端来调用您的 API。

可以在 build.yaml 文件中使用以下配置启用客户端

# build.yaml

targets:
  $default:
    builders:
      graphql_codegen:
        options:
          clients:
            - graphql
            - graphql_flutter

目前,我们支持两个客户端

客户端 graphql

在设置好 graphql 客户端后(请参阅 pub.dev/packages/graphql),您可以使用
GraphQL 代码生成来生成客户端上的新查询或变异。

使用上面的查询

# person.graphql

query FetchPerson($id: ID!) {
  fetch_person(id: $id) {
    name: full_name
  }
}

我们现在可以访问客户端

import 'person.graphql.dart';


main () async {
    final client = GraphQLClient();
    final result = await client.queryFetchPerson(
        GQLOptionsQueryFetchPerson(
            variables: VariablesQueryFetchPerson(
                id: "1",
            ),
        ),
    );
    final parsedData = result.parsedBodyQueryFetchPerson;
    print(parsedData?.fetchPerson?.name);
}

客户端 graphql_flutter

在设置好 graphql_flutter 客户端后(请参阅 pub.dev/packages/graphql_flutter),
您可以使用 GraphQL 代码生成来生成新的 QueryMutation 小部件。

使用上面的查询

# person.graphql

query FetchPerson($id: ID!) {
  fetch_person(id: $id) {
    name: full_name
  }
}

我们可以使用小部件进行查询

import 'person.graphql.dart';
import 'package:flutter/widgets.dart';

class PersonWidget extends StatelessWidget {

    @override
    Widget build(BuildContext context) {
        return GQLFQueryFetchPerson(
            options: GQLOptionsQueryFetchPerson(
                variables: VariablesQueryFetchPerson(
                    id: 'id',
                ),
            ),
            builder: (result, {fetchMore, refetch}) {
                return Text(
                    result.parsedDataQueryFetchPerson?.fetchPerson?.name ?? '...loading'
                );
            }
        );
    }

}