🙆♂️
【HTTP / GET】FlutterでREST APIを叩いて取得したデータを表示してみよう
1. はじめに
今回は、HTTPパッケージというサーバーと通信するためのパッケージを使用して開発を行っていきます。
HTTPについて理解していない方は、下記の動画を観ると良いと思います。
2. HTTPのGETメソッドを使ってデータを取得しよう
まずは、下記の記事で開発を進めていきましょう。
今回の成果物のイメージ画像は、下記の画像となります。
3. HTTPのGETメソッドのエラーハンドリングについて考えてみよう
GETメソッドで返されたRESPONSEは、statusCodeが200(成功)以外の場合でも例外が発生しないです。
ですので、その問題を解決するために、下記のメソッドを追記しました。
statusCodeが200以外の場合は、Exceptionを投げることにしています。
var jsonResponse = _response(response);
dynamic _response(http.Response response) {
switch (response.statusCode) {
case 200:
var responseJson = jsonDecode(response.body);
return responseJson;
case 400:
// 400 Bad Request : 一般的なクライアントエラー
throw Exception('一般的なクライアントエラーです');
case 401:
// 401 Unauthorized : アクセス権がない、または認証に失敗
throw Exception('アクセス権限がない、または認証に失敗しました');
case 403:
// 403 Forbidden : 閲覧権限がないファイルやフォルダ
throw Exception('閲覧権限がないファイルやフォルダです');
case 500:
// 500 何らかのサーバー内で起きたエラー
throw Exception('何らかのサーバー内で起きたエラーです');
default:
// それ以外の場合
throw Exception('何かしらの問題が発生しています');
}
}
Exceptionはcatchされ、そのExceptionごとの内容をdebugPrintで表示します。
その次に、isErrorをtrueにします。
try {
// 1. GetでResponseを取得
var response = await http.get(Uri.https(
'www.googleapis.com',
'/books/v1/volumes',
{'q': '{Flutter}', 'maxResults': '40', 'langRestrict': 'ja'}));
// 2. 問題がなければ、Json型に変換したデータを格納
var jsonResponse = _response(response);
// 3. 本の情報をリスト形式でデータを格納
setState(() {
items = jsonResponse['items'];
});
// throw Exception();
} on SocketException catch (socketException) {
// ソケット操作が失敗した時にスローされる例外
debugPrint("Error: ${socketException.toString()}");
isError = true;
} on Exception catch (exception) {
// statusCode: 200以外の場合
debugPrint("Error: ${exception.toString()}");
isError = true;
} catch (_) {
debugPrint("Error: 何かしらの問題が発生しています");
isError = true;
}
}
isErrorがtrueの場合、中央にCircularIndicatorを表示します。
isError
? const Center(
child: CircularProgressIndicator(),
)
: ListView.builder(
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Column(
children: [
ListTile(
leading: Image.network(
items[index]['volumeInfo']['imageLinks']['thumbnail'],
),
title: Text(items[index]['volumeInfo']['title']),
subtitle: Text(
items[index]['volumeInfo']['publishedDate'],
),
),
],
),
);
},
),
全体像
main.dart
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Sample',
home: MyHomePage(title: 'Flutter Sample'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List items = [];
bool isError = false;
String errorString = '';
Future<void> getData() async {
// https://www.youtube.com/watch?v=2tBbC1rZo3Q&t=489s
// HTTP:ブラウザとサーバーの間で通信を行うための規格
// GETメソッド:データをちょうだい→パラメーターはURLに含める
// 第一引数:Authority(どのWEBサーバーか)
// 第二引数:Path(そのサーバーのどこのことを指すか)
// 第三引数:Query
try {
// 1. GetでResponseを取得
var response = await http.get(Uri.https(
'www.googleapis.com',
'/books/v1/volumes',
{'q': '{Flutter}', 'maxResults': '40', 'langRestrict': 'ja'}));
// 2. 問題がなければ、Json型に変換したデータを格納
var jsonResponse = _response(response);
// 3. 本の情報をリスト形式でデータを格納
setState(() {
items = jsonResponse['items'];
});
// throw Exception();
} on SocketException catch (socketException) {
// ソケット操作が失敗した時にスローされる例外
debugPrint("Error: ${socketException.toString()}");
isError = true;
} on Exception catch (exception) {
// statusCode: 200以外の場合
debugPrint("Error: ${exception.toString()}");
isError = true;
} catch (_) {
debugPrint("Error: 何かしらの問題が発生しています");
isError = true;
}
}
dynamic _response(http.Response response) {
switch (response.statusCode) {
case 200:
var responseJson = jsonDecode(response.body);
return responseJson;
case 400:
// 400 Bad Request : 一般的なクライアントエラー
throw Exception('一般的なクライアントエラーです');
case 401:
// 401 Unauthorized : アクセス権がない、または認証に失敗
throw Exception('アクセス権限がない、または認証に失敗しました');
case 403:
// 403 Forbidden : 閲覧権限がないファイルやフォルダ
throw Exception('閲覧権限がないファイルやフォルダです');
case 500:
// 500 何らかのサーバー内で起きたエラー
throw Exception('何らかのサーバー内で起きたエラーです');
default:
// それ以外の場合
throw Exception('何かしらの問題が発生しています');
}
}
void initState() {
super.initState();
getData();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter Sample'),
),
body: isError
? const Center(
child: CircularProgressIndicator(),
)
: ListView.builder(
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Column(
children: [
ListTile(
leading: Image.network(
items[index]['volumeInfo']['imageLinks']['thumbnail'],
),
title: Text(items[index]['volumeInfo']['title']),
subtitle: Text(
items[index]['volumeInfo']['publishedDate'],
),
),
],
),
);
},
),
);
}
}
Discussion