dio + retrofit でサクサクAPIクライアント作成
記事の目的
dioとretrofitを用いてAPIクライアントを作成する方法を伝える。
前置き
flutterにはdio
というpackageがあります。Http通信のpackageです。
このディオではありません
retrofit
というpackageを利用することで、dio
のhttpのクライアントのコード生成を自動化します。
本題
clientの作成 〜 フロントで呼び出すところまでを実装します。
あらかじめコード全体を共有します!
Client 初期作成
import 'package:dio/dio.dart';
import 'package:retrofit/retrofit.dart';
part "api_client.g.dart";
final apiClient = ApiClient(Dio(_dioOption));
final _dioOption = BaseOptions(
baseUrl: 'https://hoge-api-123456',
contentType: 'application/json',
headers: {
'Authorization': 'Bearer hoge123fuga456', //実装に合わせて変更
},
);
()
abstract class ApiClient {
factory ApiClient(Dio dio) = _ApiClient;
}
まず簡単に、最低限のclient実装をしています。
ApiClientクラスは上記の記法のようにすることで自動生成されます。後ほど、クラス内に実際の関数を作成していきます。
API共通の設定はBaseOptionsで指定しています。
自動生成にはdioやretrofit以外に、以下のpackageも必要となります。
自動生成を実行するためには、ターミナルで以下のコードを叩きます。freezedでお馴染みのコードです。
dart run build_runner build --delete-conflicting-outputs
Client 関数作成
実際に関数をApiClientクラス内に作成していきます。
()
abstract class ApiClient {
factory ApiClient(Dio dio) = _ApiClient;
("/hoge/{id}")
Future<GetHogeResponse> getHoge({
() required String id,
});
("/fuga")
Future<PostFugaResponse> postFuga({
("month") required String month,
() required PostFugaRequest body,
});
}
関数の上に@GET("/hoge/{id}")
, @POST("/fuga")
と記載します。
これでメソッドとエンドポイントのpathを指定しています。
pathの動的な指定は引数で@Path
をつけることで、行います。
引数で指定するid
は、pathの/{id}
として実行されます。
("/hoge/{id}")
Future<GetHogeResponse> getHoge({
() required String id,
});
呼び出し側でidを引数指定すると実際には以下のようなURLで実行されます。
先ほど指定したBaseOptions
のbaseUrlと組み合わせられています。
https://hoge-api-123456/hoge/1234hoge
Query,Bodyの指定も@Path
と同じく@Body
,@Query
と指定して行います。
("/fuga")
Future<PostFugaResponse> postFuga({
("month") required String month,
() required PostFugaRequest body,
});
Request,Response用のModel作成
freezedの自動生成で作成しています。
import 'package:freezed_annotation/freezed_annotation.dart';
part 'post_fuga.freezed.dart';
part 'post_fuga.g.dart';
class PostFugaRequest with _$PostFugaRequest {
factory PostFugaRequest({
required String name,
required String code,
required int amount,
}) = _PostFugaRequest;
factory PostFugaRequest.fromJson(
Map<String, dynamic> json,
) =>
_$PostFugaRequestFromJson(json);
}
class PostFugaResponse with _$PostFugaResponse {
factory PostFugaResponse({required bool isValid}) = _PostFugaResponse;
factory PostFugaResponse.fromJson(
Map<String, dynamic> json,
) =>
_$PostFugaResponseFromJson(json);
}
自動生成は先ほどと同じくbuild_runner
で行っています。
dart run build_runner build --delete-conflicting-outputs
freezedの詳しい説明はこの記事では省略します。
作成したAPI処理を呼び出す
上記のようにしてAPIClientを作成したら、あとは呼び出して実行してあげるだけです!
Riverpodを利用して呼び出す
final hogeFutureProvider =
FutureProvider((ref) => apiClient.getHoge(id: '1234hoge'));
Consumer(
builder: (context, ref, _) {
final hoge = ref.watch(hogeFutureProvider);
return hoge.when(
data: (data) {
return Text(data.name);
},
loading: () {
return const Text('load中');
},
error: (error, stackTrace) {
return const Text('error');
},
);
},
),
直接UIから呼び出す
ElevatedButton(
onPressed: () {
try {
apiClient.postFuga(
month: DateFormat("yyyyMM").format(DateTime.now()),
body: PostFugaRequest(
name: "sato",
code: "1234sato",
amount: 1000,
),
);
} on DioException {
// error時の処理を記載
}
},
child: const Text("Post Fuga"),
),
最後に
以上が dio + retrofit の簡単なコードになります!
私としては、dio + retrofitを導入してからAPI処理が冗長にならず管理しやすくなったと感じています。
皆さんの開発体験に寄与できれば嬉しいです。
Discussion