はじめに
Flutterで簡単なHTTP通信を実装してたいと思い。作ってみました。
GETとPOSTしかしていません。
動作環境
この記事の動作環境は以下のとおりです。
Flutter:3.7.1
Dart SDK:2.19.1
IntelliJ IDEA:2022.2.2
完成イメージ
サンプルコード
サンプルコードはGitHubを確認してください。
サーバサイド
このサンプルのサーバサイドはjson-serverを利用しています。
json-serverの使い方は公式サイトを参照してください。
コード解説
すべてのコード解説は行いません。Flutterで作成するアプリでHTTP通信に関するところのみを説明します。
JSONのデコード・エンコード
このサンプルではjson-serverと送受信するデータはすべてJSON形式です。
そのため、JSONのデコードとエンコードが出来るようにします。
今回はBMIと体型を表すプロパティを2つ用意しています。
class BMI{
final double bmi;
final String shape;
const BMI(this.bmi, this.shape,);
Map<String, dynamic> toMap() {
return {
'bmi': this.bmi,
'shape': this.shape,
};
}
BMI.fromJson(Map<String, dynamic> map)
: bmi= map['bmi'], shape= map['shape'];
}
今回実装したBMIクラスの特徴は、JSONに変換するfromJSONメソッドとJSONからBMIクラスのオブジェクトに変換するtoMapメソッドです。
JSONに変換する処理
オブジェクトからJSONに変換するためにはjsonEncode関数を呼び出します。引数はObject型を受け取りますが、下記のデータ型であれば直接エンコードできます。
- 数値
- Boolean
- 文字列
- NULL
- リスト
- 文字列をキーとするマップ
そのため、BMIクラスにMapに変換するメソッドを用意しておきます。
Map<String, dynamic> toMap() {
return {
'bmi': this.bmi,
'shape': this.shape,
};
}
JSONからオブジェクトに変換する処理
JSON文字列をオブジェクトに変換するために、jsonDecode関数を呼び出します。
戻り値は、引数に渡すJSON文字列によって変わります。引数に渡すJSON文字列がリスト形式のJSONの場合はList、JSONオブジェクトの場合はMap形式で受け取れます。
JSON文字列がリスト形式であってもリストの要素はJSONオブジェクトであるため、Map形式で個々のデータを取得できます。Map形式で受け取った場合、値はdynamic形です。
そのため、Map形式からオブジェクトに変換する処理を用意しておく必要があります。
サンプルコードではtoMapメソッドとして定義しました。
BMI.fromJson(Map<String, dynamic> map)
: bmi= map['bmi'], shape= map['shape'];
HTTP通信
サンプルコードではHTTPのGETメソッドとPOStメソッドを使っています。
まずはコード全体を確認しましょう。
import 'dart:convert';
import 'package:bmi_sample/model/bmi.dart';
import 'package:http/http.dart' as http;
class BMIHttpClientNative {
// json-serverを実行しているIPアドレスを指定
final String _ipAddress = "XXX.XXX.XXX.XXX";
Future<List<BMI>> getBmi() async {
List<BMI> list = [];
var uri = Uri.parse('http://$_ipAddress:3000/bmi');
var response = await http.get(uri);
Iterable iterable = jsonDecode(response.body);
var conertList = iterable.map((e) => BMI.fromJson(e)).toList();
list.addAll(conertList);
return list;
}
Future<int> postBmi(BMI bmi) async {
http.Response? response;
response = await http.post(
Uri.parse('http://$_ipAddress:3000/bmi'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(bmi.toMap()),
);
return response.statusCode;
}
}
準備
DartでHTTP通信するためには、HTTPクライアントを利用します。
そのため、HTTPクライアントのライブラリーを追加しなければなりません。
サンプルではpubspec.yaml
に追記してビルド時に追加しています。
追加方法の詳細は公式サイトを参照してください。
dependencies:
http: ^0.13.5
import文
ライブラリーを追加するだけでは利用できないのでHTTPクライアントをインポートします。
import 'package:http/http.dart' as http;
非同期処理
HTTP通信処理は一般的に非同期処理で実装します。
そのため、GETとPOSTを処理している関数は非同期処理で実装しています。
非同期処理を実装するためのasyncについては公式サイトを確認してください。
Future<int> postBmi(BMI bmi) async {
・・・省略・・・
}
URIの準備と通信
HTTPクライアントの準備ができたら、接続する先のURIを用意します。
URI準備するにはUriクラスのparseメソッドを呼び出し生成します。
Uri.parse('http://$_ipAddress:3000/bmi')
HTTP通信の準備が整いました。GETメソッドとPOSTメソッドで通信を行います。
GETメソッド
今回のサンプルのGETメソッドでのHTTP通信ではデータを送らないため、http.get関数にUriオブジェクトを渡しています。
第2引数にはヘッダー情報をMap型で渡せます。
await http.get(uri);
通信処理部分はawaitでHTTP通信処理が完了を待ちます。
POSTメソッド
今回のサンプルでは、POSTでJSON文字列でBMIと体型を送信しています。
そのため、2つの前処理をしています。
- ヘッダーの準備
- オブジェクトからJSON文字列への変換
ヘッダーはGETメソッドでも説明した通り、Map型で準備します。
<String, String>{
'Content-Type': 'application/json; charset=UTF-8',
}
JSON文字列への変換はすでに説明しているとおり、jsonEncode関数にMap型のデータを渡しています。
jsonEncode(bmi.toMap())
JSON文字列とヘッダーをhttp.POST関数を呼び出してHTTP通信を行います。
引数は下記の4つです。
型 | 説明 | 必須 or オプション |
---|---|---|
Uri型 | 接続先のURL | 必須 |
Map型 | ヘッダー情報 | オプション |
Object型 | HTTP通信のボディで送信するデータ。String、List、Mapを引数に渡せます。 | オプション |
Encoding型 | エンコードを指定します。デフォルトはutf-8です。 | オプション |
今回のサンプルではUriとボディのみを渡しています。
また、GETメソッド同様にawaitでHTTP通信の処理が完了するまで待ちます。
await http.post(
Uri.parse('http://$_ipAddress:3000/bmi'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(bmi.toMap()),
);
レスポンス
HTTP通信が完了するとResponse型で返ってきます。
var response = await http.get(uri);
Iterable iterable = jsonDecode(response.body);
response = await http.post(
・・・省略・・・
);
return response.statusCode;
今回はbodyプロパティとstatusCodeプロパティを利用しています。必要に応じて他のプロパティを利用してください。
まとめ
標準APIでHTTP通信を行ってみましたが、比較的使いやすく感じます。
外部ライブラリーを使うとどれくらい楽に実装できるか気になるのでいつか調べてみます。