ドライバー用アプリ『GOドライバー』を開発しているFlutterエンジニアの井戸田です。
本記事では、『GOドライバー』に chuck_interceptor を導入して得られた知見を紹介します
chuck_interceptorを導入した背景
私たちの開発チームでは、アプリケーションのネットワーク通信に起因する処理の不具合に悩んでいました。
不具合が発生した際、その原因がアプリ側にあるのか、API側にあるのかを迅速かつ正確に判断するのが困難でした。例えば社内の方から「特定の機能が正しく動作しない」という報告があった場合、 その問題がFlutterのコードによるものなのか 、またはAPIからのレスポンス に原因があるものなのか特定するために、詳細にヒアリングする必要がありました。 問題の再現方法を特定するために何度もやり取りを繰り返すことで、時間を費やしおり、コミュニケーションコストを増大させていました。
そのためchuck_intercepterを導入しようと決めました。
chuck_interceptorとは
https://pub.dev/packages/chuck_interceptor
chuck_interceptorはAndroidライブラリであるChuckとChuckerからインスパイヤーされたFlutterのライブラリで、ネットワークリクエストをデバッグするためのツールです。
このライブラリは、HTTPリクエストとレスポンスをインターセプトし、詳細な情報を提供します。API通信の問題の特定と解決を行うために役立ちます。
chuck_interceptorを使うことで次のような利点があります。
またFlutter内で完結できるので、非エンジニアの方でも確認がしやすいと感じています。
導入方法
今回はDioを使った方法で紹介します。
他にも dart:io
パッケージである HttpClient
や、 http 、 Chopper での導入方法もREADMEに記載されているので、ご覧ください。
パッケージのインストール方法
chuck_interceptorとdio以外にも、 依存性の解決のためにflutter_riverpodも入れておきます。
dependencies: flutter: sdk: flutter chuck_interceptor: ^2.1.6 dio: ^5.4.3+1 flutter_riverpod: ^2.5.1
Chuckを定義
final chuckProvider = Provider<Chuck>( (ref) => Chuck(), );
今回はオプションを指定していませんが、Chuckにはさまざまなオプションがあり必要に応じて設定できます。
オプション名 | default | 詳細 |
---|---|---|
showNotification | true | リクエストをキャッチした際に通知するか。 中ではflutter_local_notificationsが使われているようです。 |
showInspectorOnShake | false | デバイスの揺れでインスペクターページを開くか(センサー付きの物理的なものでのみ機能する) |
darkTheme | false | インスペクターページをdarkテーマで表示させるか |
notificationIcon | @mipmap/ic_launcher | 通知のアイコン |
maxCallsCount | 100 | 保存するコール数 |
directionality | null | アプリのDirectionality。nullに設定されている場合は、アプリのDirectionalityを使用。 |
インターセプターを設定
final dioProvider = Provider((ref) { final options = BaseOptions( baseUrl: 'http://XXX', headers: { Headers.contentTypeHeader: Headers.jsonContentType, }, ); return Dio(options) ..interceptors.add( ref.read(chuckProvider).getDioInterceptor(), ); });
dioの interceptors
にchuck_interceptorの getDioInterceptor
を追加します。
ナビゲーションキーを設定
MaterialApp( // ... navigatorKey: ref.read(chuckProvider).getNavigatorKey(), // ... );
インスペクターページを表示させるためにナビゲーションキーを設定します。
設定は以上です。実際に動かしてみます。
実際に動かしてみる
dioでAPIをリクエスト後に chuck.showInspector();
を呼び出すか、またはChuckクラスの showInspectorOnShake
が true
の場合は端末を振った場合、下記のようなインスペクターページが表示されます。
一覧
リクエストしたAPIの一覧が表示され、各アイテムとしてはエンドポイント、HTTPステータス、通信時間、応答速度、送受信したデータサイズが表示されます。
詳細
Overview | Request | Response | Preview | Error |
---|---|---|---|---|
- Overview
- Methodやエンドポイント、リクエストした時間、終わった時間等が表示されます
- Request
- Response
- レスポンスの詳細情報(返ってきた時間、HTTPステータス、headerの情報、body情報)が表示されます
- こちらもレスポンスの情報全て表示されるため機密情報等シェアしたくない情報が表示されている場合は、注意する必要があるかもしれません。
- Preview
- レスポンスのbody情報が表示されます
- Error
- DioExceptionなどExceptionが発生した場合、そのエラー情報が表示されます
またFloatingActionButtonをタップすることで、この情報をシェアすることができます。
(内部ではshare_plusを使っています。)
出力はテキスト形式で、下記のような形です。
Chuck - HTTP Inspector App name: Chucksample Package: [パッケージ名] Version: 1.0.0 Build number: 1 Generated: 2024-05-26T01:08:21.647134 =========================================== Id: 856632419 ============================================ -------------------------------------------- General data -------------------------------------------- Server: localhost Method: GET Endpoint: /api/v1/articles/search?q=title&created_at=2024/01/01 Client: Dio Duration 74 ms Secured connection: false Completed: true -------------------------------------------- Request -------------------------------------------- Request time: 2024-05-26 01:06:27.617510 Request content type: application/json Request cookies: [] Request headers: { "content-type": "application/json" } Request size: 0 B Request body: Body is empty -------------------------------------------- Response -------------------------------------------- Response time: 2024-05-26 01:06:27.691023 Response status: 200 Response size: 269 B Response headers: { "connection": "[keep-alive]", "keep-alive": "[timeout=5]", "transfer-encoding": "[chunked]", "date": "[Sat, 25 May 2024 16:06:27 GMT]" } Response body: { "articles": [ { "id": 1, "title": "title1", "description": "description1", "created_at": "2024/01/01" }, { "id": 2, "title": "title2", "description": "description2", "created_at": "2024/01/01" } ] } -------------------------------------------- Curl -------------------------------------------- curl -X GET -H 'content-type: application/json' 'http://localhost/api/v1/articles/search?q=title&created_at=2024/01/01' ==============================================
導入後の結果
chuck_interceptorを導入したことで、大きく2点改善されました。
1点目は原因を特定する速さです。
FlutterアプリケーションとAPIの間でやり取りされるすべてのHTTPリクエストとレスポンスを詳細に監視できるようになり、 「Flutter側、API側のどちらの問題なのか」 を迅速に特定することが可能となりました。
さらに、API側に問題がある場合、 「どの値が期待と異なるのか」 を正確に特定することができるようになりました。
2点目はコミュニケーションコストです。
不具合が発生した際には、どのような操作を行ったか確認した上で、chuck_intercepterのログを受け取るだけで済むことが多くなりました。
具体的には、以下の手順を踏むことで、問題を迅速に特定し解決策を見つけることができました。
- 不具合を発見した方から、開発者がインターセプターページの一覧のスクリーンショットを受け取る
- 開発側がそのスクリーンショットから問題のある可能性の高いAPIを推測し、不具合を発見した方にAPIログが欲しいと依頼する
- 不具合を発見した方から、開発側がそのAPIログを受け取る
その結果、コミュニケーションの回数が減り、情報の伝達がスムーズになりました。
chuck_interceptorの導入は、技術的な問題解決を容易にするだけでなく、チーム内外のコミュニケーションを改善し、開発プロセスを最適化するためのステップとなったと感じています。
最後に
chuck_interceptorを導入したことで、開発者以外の端末で発生した不具合でも原因の特定がしやすくなりました。
またコミュニケーションコストも削減にも公開がありました。
もし不具合が発生した際の問題の切り分けが難しいと感じている方がいらっしゃいましたら、導入も簡単にできますので、ご検討ください。
最後まで読んでいただきありがとうございました。