📚

Flutter で型安全 & 簡単に GraphQL のクエリを発行できる hooks を生成できるライブラリを作りました!

2022/01/01に公開

こちらです。Flutter & GraphQL 勢な方は是非使ってみてください。
(そしていいなと思ったらぜひスターください⭐️)
https://github.com/kazuyaseki/graphql-codegen-flutter-artemis-hooks

モチベーション

私は React 出身者なのですが、React + Apollo のような構成でアプリケーションを作る時、graphql-codegen で次のような hooks を生成するのが非常に体験良かったです。

export function useFetchUserQuery(baseOptions?: ApolloReactHooks.QueryHookOptions<FetchUserQuery, FetchUserQueryVariables>) {
    return ApolloReactHooks.useQuery<FetchUserQuery, FetchUserQueryVariables>(FetchUserDocument, baseOptions);
}

※ こちらのプラグインを withHooks を true にして使った時に生成されるコードです
https://www.graphql-code-generator.com/plugins/typescript-react-apollo

Flutter でも同じ体験で開発したい!と思って作ったのがこちらのプラグインです。
https://github.com/kazuyaseki/graphql-codegen-flutter-artemis-hooks

Flutter では artemis という型を生成してくれるものはあるので、それを前提に使うものとなっています。

例えばこんなクエリを .graphql ファイルとして定義したとします。

query ExampleQuery {
  objects {
    id
    name
  }
}

mutation TestMutation($variable: String!) {
  testMutation(variable: $variable) {
    result
  }
}

このプラグインを使うと次のような hooks の関数が生成されます。

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:gql/ast.dart';
import 'package:your_project/your_artemis_generated/graphql_api.dart';

QueryResult useQuery<DataType>(BuildContext context, DocumentNode query,
    [Map<String, dynamic>? variables]) {
  final client = GraphQLProvider.of(context).value;
  final state =
      useState<QueryResult>(QueryResult(source: QueryResultSource.network));

  useEffect(() {
    late Future<QueryResult> promise;

    if (variables != null) {
      promise = client.query(
        QueryOptions(document: query, variables: variables),
      );
    } else {
      promise = client.query(
        QueryOptions(document: query),
      );
    }
    promise.then((result) {
      state.value = result;
    });

    return () {};
  }, []);
  return state.value;
}

class ExampleQuery$QueryReturnType {
  bool isLoading;
  OperationException? exception;
  ExampleQuery$Query? data;

  ExampleQuery$QueryReturnType(this.isLoading, this.exception, this.data);
}

ExampleQuery$QueryReturnType useExampleQueryQuery<DataType>(BuildContext context) {
  final result = useQuery<ExampleQuery$Query>(context, EXAMPLE_QUERY_QUERY_DOCUMENT);
  return ExampleQuery$QueryReturnType(result.isLoading, result.exception, result.data == null ? null : ExampleQuery$Query.fromJson(result.data!));
}

class TestMutation$MutationReturnType {
  bool isLoading;
  OperationException? exception;
  TestMutation$Mutation? data;

  TestMutation$MutationReturnType(this.isLoading, this.exception, this.data);
}

TestMutation$MutationReturnType useTestMutationQuery<DataType>(BuildContext context, TestMutationArguments variables) {
  final result = useQuery<TestMutation$Mutation>(context, TEST_MUTATION_MUTATION_DOCUMENT, variables.toJson());
  return TestMutation$MutationReturnType(result.isLoading, result.exception, result.data == null ? null : TestMutation$Mutation.fromJson(result.data!));
}

そうしたら後は上記ファイルを import して hooks を使うだけです!🔥

class PageWidget extends HookWidget {
  const PageWidget({Key key}) : super(key: key);

  
  Widget build(BuildContext context) {
    final queryResult = useExampleQueryQuery(context);
    final mutationResult = useTestMutationQuery(context, TestMutationArguments(variable: ""));

    return ...
  }
}

使い方

README にも書いてはありますが、最後に使い方の解説をします。

インストール

npm i --save-dev graphql-codegen-flutter-artemis-hooks

graphql-codegen の設定ファイルを作成

次のようにスキーマや .graphql ファイルのパス、artemis で生成されたファイルへのパスなどを記入ください。

codegen.yml
schema: your_schema_file.graphql
documents: './your_project/**/*.graphql'
generates:
  your_project/generated_hooks.dart:
    config:
      artemisImportPath: package:your_project/your_artemis_generated/graphql_api.dart
    plugins:
      - graphql-codegen-flutter-artemis-hooks

graphql-codegen を実行

もし graphql-codegen 自体をインストールされていない場合は次の @graphql-codegen/cli をインストールしてください。

npm i --save-dev @graphql-codegen/cli

そして package.json に次の script を追加して npm run codegen してください!!

{
  "scripts": {
    "codegen": "graphql-codegen"
  },
}

以上です、ぜひご活用ください!!

Discussion