HTTP GETでREST APIにアクセスする
HTTP GETでREST APIにアクセスするHTTPクライアントクラスを作ります。
サーバがJSON形式のデータを返すことを想定します。
HTTPクライアントはWidgetが共通で利用するためシングルトンクラスにします。
実際に開発する時は、サーバ側も同時並行で開発することがよくあります。
そのため、サーバにアクセスしないでテストするためのスタブも実装します。
スタブとは、一言でいうとダミーデータを返す代用プログラムのことです。
httpパッケージのインストール
まずhttpをインストールします。pubspec.yamlのdependenciesブロックにhttp:を追加します。
⚠yamlファイルはインデントの位置も意味がありますので注意
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
http:
追加したらターミナルでコマンドを実行してインストールします。またはAndroid Studioの場合はボタンが自動的に表示されるのでそれをクリックするだけでOKです。
flutter packages get
スタブデータの準備
実際にHTTPアクセスするサイトはjsonplaceholderを利用させてもらいました。スタブデータもそれと同じモデルを作成しました。
適当なdartファイルにスタブデータだけを書いておき、利用する側でimportすることにします。
const STUB_MODE = false;
const stubPostsResponse = '''
[
{
"userId": 1,
"id": 1,
"title": "title1",
"body": "Test body1."
},
{
"userId": 1,
"id": 2,
"title": "title2",
"body": "Test body2. Test body2."
},
{
"userId": 1,
"id": 3,
"title": "title3",
"body": "Test body3. Test body3. Test body3."
}
]
''';
HTTPクライアントの実装
HTTPリクエストをコンソールにprintしたいのでhttp.BaseClientを継承してsend()を@overrideします。また、ここでHTTPヘッダを変更することができます。
実際のサーバアクセスもスタブもFuture<http.Response>を返します。
スタブの場合はFuture.delayed()で5秒後にダミーデータを返すようにします。
class SampleService extends http.BaseClient {
static SampleService _instance;
final _inner = http.Client();
factory SampleService() => _instance ??= SampleService._internal();
SampleService._internal();
@override
Future<http.StreamedResponse> send(http.BaseRequest request) async {
request.headers['User-Agent'] = 'Sample Flutter App.';
print('----- API REQUEST ------');
print(request.toString());
if (request is http.Request && request.body.length > 0) {
print(request.body);
}
return _inner.send(request);
}
/// APIコール
Future<http.Response> getPosts() async {
if (STUB_MODE) {
// スタブ
final res = http.Response(stubPostsResponse, 200, headers: {
HttpHeaders.contentTypeHeader: 'application/json; charset=utf-8'
});
return Future.delayed(const Duration(seconds: 5), () => res);
} else {
// APIサーバアクセス
final url = 'https://jsonplaceholder.typicode.com/posts';
return get(url);
}
}
}
JSONデータのデシリアライズ
JSONデータをList<Post>にデシリアライズしたいので、まずPostクラスを作成します。
class Post {
int userId;
int id;
String title;
String body;
Post(this.userId, this.id, this.title, this.body);
// Named constructor
Post.fromJson(Map<String, dynamic> json) {
userId = json['userId'];
id = json['id'];
title = json['title'];
body = json['body'];
}
}
使う側ではこんな感じで実装すればList<Post>が作成できますね。
final list = json.decode(response.body);
final posts = list.map((post) => Post.fromJson(post)).toList();
一覧画面の作成
最後にStatefulWidgetのinitState()でデータを取得してデシリアライズする処理を実装します。
List<Post> postsはPostの配列です。
ListView.builder()で一覧画面を実現します。
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:http_client/stub.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: PostsListScreen('タイトル'),
);
}
}
class PostsListScreen extends StatefulWidget {
final title;
PostsListScreen(this.title);
@override
_PostsListScreenState createState() => _PostsListScreenState();
}
class _PostsListScreenState extends State<PostsListScreen> {
List<Post> posts = [];
@override
void initState() {
SampleService().getPosts().then((response) {
final list = json.decode(response.body);
if (list is List) {
setState(() {
posts = list.map((post) => Post.fromJson(post)).toList();
});
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
padding: EdgeInsets.all(10),
child: ListView.builder(
padding: EdgeInsets.all(10),
itemCount: posts.length,
itemBuilder: (context, int index) {
return Column(children: <Widget>[
ListTile(title: Text(posts[index].body)),
Divider(height: 2.0, color: Colors.grey),
]);
},
),
),
);
}
}
コード全体
まとめ
今回はかんたんにHTTPクライアントを実装してみました。
画面表示はsetState()を使っていますが、State managementの観点で理想の型ではありません。
また、実際の開発現場ではPostのようなモデルクラスをたくさん作成する場合がありますが、json_serializableパッケージを使うと楽に実装できます。それはまた別の機会に。
この記事が気に入ったらサポートをしてみませんか?