プロジェクト作成
公式ドキュメントにそってセットアップ
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 をプロジェクトルートに保存
# 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 {
// ...
@override
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,
),
],
),
)
]),
);
});
},
),
);