【Flutter】楽天ブックスAPIで書籍検索アプリを作る
今回は楽天ブックスAPIを使って書籍の検索アプリを作ってみようと思います。
目標
以下の要件を実現することを目標として進めます。
・楽天ブックス系APIを叩いて書籍の情報を取得する
→書影、タイトル、著者、出版社、発売日を一覧形式で画面に表示
・画面上部に検索キーワードの入力フォームを作る
・検索ボタンを押すと、入力された文字列を使って検索結果の一覧を表示させる
APIを使うための準備
アプリを作り始める前に楽天APIを使えるようにする準備をしましょう。
リンク:https://webservice.rakuten.co.jp/
私はこちらの方などのサイトを参考にしました。Application IDに関しては十分に気をつけて管理する必要があります。
パッケージをインストール
今回使用するパッケージは以下の通りです。
dependencies:
flutter:
sdk: flutter
http: ^0.13.4 #httpパッケージのバージョンを指定
ソースコード
アプリのエントリーポイントやroot widgetを定義し、書籍検索画面を含むFlutterアプリケーションの基本的な構造となる部分のコードを作ります。home プロパティにBookListScreen クラスのインスタンスを指定していますが、これは画面として書籍リスト画面を表示させるためのものです。
main.dart
import 'package:flutter/material.dart';
import 'book_list_screen.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Book Search',
theme: ThemeData(
primarySwatch: Colors.red,
),
home: BookListScreen(),
);
}
}
book_list_screen.dart
それでは次に、main.dartで記述したBookListScreen クラスを別ファイルに作っていきます。今回はこのファイルをmain.dartと同じディレクトリに置くことにします。
表示させる本の数ですが、楽天ブックスのページを見ていただくとわかるように1ページあたり最大で30冊までなので、このアプリでも同様に最大で30冊まで表示させる仕様になります。
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'bookinfo.dart';
class BookListScreen extends StatefulWidget {
@override
_BookListScreenState createState() => _BookListScreenState();
}
class _BookListScreenState extends State<BookListScreen> {
final TextEditingController _searchController = TextEditingController();//キーワード入力用に_searchController を作成
List<Book> books = [];//書籍情報を保持するためのリスト
@override
void dispose() {
_searchController.dispose();
super.dispose();
}
Future<void> fetchBooks(String keyword) async {//書籍を検索するためのメソッド
final appId = 'hoge';//ここにApplication IDを書く
final apiUrl = 'https://app.rakuten.co.jp/services/api/BooksBook/Search/20170404';
final url = Uri.parse('$apiUrl?applicationId=$appId&title=${Uri.encodeQueryComponent(keyword)}');
final response = await http.get(url);
if (response.statusCode == 200) {
final data = json.decode(response.body);
List<Book> fetchedBooks = [];
for (var bookData in data['Items']) {
String imageUrl = bookData['Item']['largeImageUrl'];
String title = bookData['Item']['title'];
String author = bookData['Item']['author'];
String publisher = bookData['Item']['publisherName'];
String pubdate = bookData['Item']['salesDate'];
fetchedBooks.add(Book(
imageUrl: imageUrl,
title: title,
author: author,
publisher: publisher,
pubdate: pubdate,
));
}
setState(() {
books = fetchedBooks;
});
}
}
void handleSearch() {//検索ボタンが押されたときの処理
String keyword = _searchController.text.trim();
if (keyword.isNotEmpty) {
fetchBooks(keyword);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('書籍検索'),
),
body: Column(
children: [
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
borderRadius: BorderRadius.circular(8.0),
),
margin: EdgeInsets.all(16.0),
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
children: [
Expanded(
child: TextField(
controller: _searchController,
decoration: InputDecoration(
labelText: 'キーワード検索',
border: InputBorder.none,
),
),
),
SizedBox(width: 16.0),
ElevatedButton(
onPressed: handleSearch,
child: Text('検索'),
),
],
),
),
Expanded(
child: ListView.separated(
itemCount: books.length,
separatorBuilder: (BuildContext context, int index) {
return Divider(
thickness: 1.0,
color: Colors.grey,
);
},
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: Image.network(books[index].imageUrl),
title: Text(books[index].title),
subtitle: Text(
'著者: ${books[index].author}\n出版社: ${books[index].publisher}\n発売日: ${books[index].pubdate}',
),
);
},
),
),
],
),
);
}
}
bookinfo.dart
最後に、書籍情報を表すBookクラスを定義していきます。
class Book {
final String imageUrl;//書影
final String title;//タイトル
final String author;//著者
final String publisher;//出版社
final String pubdate;//発売日
Book({
required this.imageUrl,
required this.title,
required this.author,
required this.publisher,
required this.pubdate,
});
}
完成イメージ(スクショ)
線型代数と入力して検索した場合を見てみましょう。
画面を上下にスクロールすると30冊まで表示されていることが確認できるかと思います。
最後までご覧いただきありがとうございました。
Discussion