⛴️

Flutter: Ferry を使った GraphQL 簡易アプリの作成

2021/10/17に公開

プロジェクト作成

公式ドキュメントにそってセットアップ

https://ferrygraphql.com/docs/setup/

ghq create gqlflutter
flutter create .

パッケージインストール

flutter pub add gql_http_link
flutter pub add ferry_flutter # 追加
flutter pub add -d ferry_generator
flutter pub add -d build_runner

スキーマファイルをダウンロード

参考
https://ferrygraphql.com/docs/codegen

スキーマダウンロードするツールをインストール

npm install -g get-graphql-schema

スキーマをダウンロード

今回はポケモンのGraphQL API https://graphql-pokemon2.vercel.app を利用させてもらいました。ありがとうございます。

get-graphql-schema https://graphql-pokemon2.vercel.app > lib/schema.graphql

コードを書く

GraphQL クエリーの用意

ポケモンデータを取得するクエリを書く

# lib/graphql/all_pokemon.graphql
query AllPokemon($first: Int!) {
  pokemons(first: $first) {
    id
    name
    maxHP
    image
  }
}

build.yaml を作成

こちらの yaml をプロジェクトルートに保存

https://ferrygraphql.com/docs/codegen#build-generated-classes

# build.yaml
targets:
  $default:
    builders:
      gql_build|schema_builder:
        enabled: true
      gql_build|ast_builder:
        enabled: true
      gql_build|data_builder:
        enabled: true
        options:
          schema: your_package_name|lib/schema.graphql
      gql_build|var_builder:
        enabled: true
        options:
          schema: your_package_name|lib/schema.graphql
      gql_build|serializer_builder:
        enabled: true
        options:
          schema: your_package_name|lib/schema.graphql

      ferry_generator|req_builder:
        enabled: true
        options:
          schema: your_package_name|lib/schema.graphql

GraphQL クエリから Dart コードを生成

flutter pub run build_runner build

lib/graphql は下記のようになる

all_pokemon.data.gql.dart
all_pokemon.data.gql.g.dart
all_pokemon.graphql
all_pokemon.req.gql.dart
all_pokemon.var.gql.dart

GraphQL client の準備

GraphQL Client を取得できるメソッドを準備

class MyHomePage extends StatefulWidget {
  // ...
  
  Client? _client;  
  
  Client get client {
    if (_client == null) {
      final link = HttpLink('https://graphql-pokemon2.vercel.app');
      return _client = Client(link: link);
    } else {
      return _client!; // NOTE: ! 消せないの?
    }
  }
  // ...
}

ポケモンをリスト表示

ferry には ferry_flutter パッケージで flutter で使いやすいように Widget が用意されています。

Operation widget を使うと良い感じにデータ取得ができます。

class MyHomePage extends StatefulWidget {
  // ...
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Operation(
        client: client,
        operationRequest: GAllPokemonReq((b) => b..vars.first = 151),
        builder: (BuildContext context,
            OperationResponse<GAllPokemonData, GAllPokemonVars>? response,
            Object? error) {
          if (response == null || response.loading) {
            return const Center(child: CircularProgressIndicator());
          }

          final pokemons = response.data?.pokemons ?? BuiltList();

          return ListView.builder(
              itemCount: pokemons.length,
              itemBuilder: (context, index) {
                final pokemon = pokemons[index];

                return Card(
                  child: Row(children: <Widget>[
                    SizedBox(
                      child: Image.network(
                          pokemon.image ?? 'https://placehold.jp/150x150.png'),
                      width: 100,
                    ),
                    Padding(
                      padding: const EdgeInsets.only(left: 20),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text('Name: ${pokemon.name ?? '[unknown]'}'),
                          Text(
                            'MAX HP: ${pokemon.maxHP}',
                            textAlign: TextAlign.left,
                          ),
                        ],
                      ),
                    )
                  ]),
                );
              });
        },
      ),
    );

完成

こんな感じでポケモンの一覧が表示されれば完成
完成画面

Discussion