graphql_flutter + graphql_codegenを使用したFlutterでのGraphQL
はじめに
FlutterでGraphQLを使用しようと調査するなかで、graphql_flutter + graphql_codegenの組み合わせが使いやすそうでした。
使いやすそうと思った点は、GraphQLのスキーマからgraphql_codegenによるコードの自動生成です。
queryやmutationを記載し、それをもとにgraphql_flutterのコードも自動生成され、データの構造や型もわかります。
サンプルコードを用意したので、それをもとに紹介したいと思います。
サンプルコード
サンプルコードはこちらです。
GraphQLサーバーはこちらを使用させていただきました。
画面イメージ
環境
- Flutter: 3.0.4
- graphql_flutter: 5.1.0
- graphql_codegen: 0.9.0
- build_runner: 2.1.11
- flutter_hooks: 0.18.5+1
サンプルコードの内容
GraphQLのスキーマからの自動生成
まずは、GraphQLのスキーマからコードを自動生成します。
SDL取得
https://graphql-pokemon2.vercel.app からSDLを取得します。
取得方法はいろいろありますが、私はChrome拡張のAltair GraphQL Clientを使用しました。
以下のパスに保存しています。
lib/graphql/schema.graphql
Query記載
GraphQLよりデータを取得するため、Queryを記載します。
lib/graphql/pokemons.graphql
query Pokemons($first: Int!) {
pokemons(first: $first) {
id
number
name
image
}
}
自動生成の設定
graphql_codegenはbuild_runnerによる自動生成のため、そちらの設定をしていきます。
build.yaml
targets:
$default:
builders:
graphql_codegen:
options:
scopes:
- lib/graphql/**
clients:
- graphql
- graphql_flutter
build_runner実行し、コードの自動生成
build_runnerを実行すると、以下のファイルが作成されます。
flutter pub run build_runner build
- lib/graphql/schema.graphql.dart
- lib/graphql/pokemons.graphql.dart
- lib/graphql/pokemons.graphql.g.dart
GraphQLクライアントの作成
SDL, Queryからコードが自動生成されたので、次にgraphql_flutterを使用してGraphQLのクライアントを作成します。
Hiveの初期化
GraphQLのクライアントのキャッシュにHiveを使用しているので、そちらの初期化を行います。
lib/main.dart
// Flutter imports:
import 'package:flutter/material.dart';
// Package imports:
import 'package:graphql_flutter/graphql_flutter.dart';
// Project imports:
import 'package:flutter_graphql_pokemon/app_root.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await initHiveForFlutter();
runApp(const AppRoot());
}
GraphQLのクライアントを作成
GraphQLのクライアントを作成します。
lib/app_root.dart
// Flutter imports:
import 'package:flutter/material.dart';
// Package imports:
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
// Project imports:
import 'package:flutter_graphql_pokemon/ui/main/main_page.dart';
class AppRoot extends HookConsumerWidget {
const AppRoot({super.key});
Widget build(BuildContext context, WidgetRef ref) {
final link = HttpLink('https://graphql-pokemon2.vercel.app');
final client = ValueNotifier<GraphQLClient>(
GraphQLClient(
link: link,
cache: GraphQLCache(store: HiveStore()),
),
);
return GraphQLProvider(
client: client,
child: const MaterialApp(title: 'GraphQL Pokémon', home: MainPage()),
);
}
}
Queryから一覧を表示
useQuery$Pokemons
が自動生成されたQueryのメソッドになります。
取得したデータ構造や型も定義されたものが取得できています。
lib/ui/main/main_page.dart
// Flutter imports:
import 'package:flutter/material.dart';
// Package imports:
import 'package:hooks_riverpod/hooks_riverpod.dart';
// Project imports:
import 'package:flutter_graphql_pokemon/graphql/pokemons.graphql.dart';
class MainPage extends HookConsumerWidget {
const MainPage({super.key});
Widget build(BuildContext context, WidgetRef ref) {
final appBar = AppBar(
title: const Text('GraphQL Pokémon'),
);
final queryResult = useQuery$Pokemons(
Options$Query$Pokemons(
variables: Variables$Query$Pokemons(first: 200),
),
);
final result = queryResult.result;
Widget bodyChild;
if (result.isLoading) {
bodyChild = const Center(child: CircularProgressIndicator());
} else if (result.hasException) {
bodyChild = Text(result.exception.toString());
} else {
final pokemons = result.parsedData?.pokemons ?? [];
bodyChild = ListView.builder(
itemCount: pokemons.length,
itemBuilder: (context, index) {
final pokemon = pokemons[index];
return ListTile(
leading: Image.network(pokemon?.image ?? ''),
title: Text(pokemon?.name ?? ''),
);
},
);
}
final body = RefreshIndicator(
onRefresh: queryResult.refetch,
child: bodyChild,
);
return Scaffold(
appBar: appBar,
body: body,
);
}
}
まとめ
graphql_flutter + graphql_codegenによるFlutterでのGraphQLはいかがだったでしょうか?
FlutterでGraphQLを使う場合、artemisやferryがあると思いますが、graphql_flutter + graphql_codegenも選択肢に加えてみてはどうでしょう。
Discussion