この章では Qiita API をアクセストークンを使って呼び出し、返されたデータをモデルクラスに変換する処理を実装していきます。
アクセストークンの秘匿化
Qiita API を呼び出すにあたって、先に作成したアクセストークンをリクエストに含める必要があります。
コード上にベタ打ちでアクセストークンを記述することもできますが、それでは Github などにコードを公開した際にアクセストークンが漏れてしまいます。
そこで、今回はこういったアクセストークンを秘匿化するための、flutter_dotenv
というパッケージを使ってみましょう。
1. パッケージのインストール
まずは、flutter_dotenv
をインストールします。
$ flutter pub add flutter_dotenv
.env
ファイルの作成
2. 次に、flutter_dotenv
が読み込む .env
ファイルを作成します。
ルートディレクトリの直下に .env
ファイルを作成し、以下のようにアクセストークンを記述します。
QIITA_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxx となっている部分に先ほど作成したアクセストークンを記述してください。
.gitignore
に .env
を追加
3. .env
ファイルが github にプッシュされてしまうとアクセストークンが公開されてしまうので.gitignore
に .env
ファイルを追加します。
# .env ファイルを追加
.env
.env
を登録
4. assets として次に、pubspec.yaml
に .env
ファイルを assets として登録します。
flutter:
uses-material-design: true
assets:
- .env # <- ここに追記
.env
ファイルの読み込み
5. 最後に、main.dart
で .env
ファイルを読み込みます。
import 'package:flutter_dotenv/flutter_dotenv.dart';
Future<void> main() async {
await dotenv.load(fileName: '.env');
runApp(MyApp());
}
これで、dotenv
で読み込んだアクセストークンは、どこのファイルからもdotenv.env['QIITA_ACCESS_TOKEN']
で取得できるようになります。
final String token = dotenv.env['QIITA_ACCESS_TOKEN']); // .env に記述したアクセストークンを取得
これで準備は整いました。
API 通信の実装
それでは Qiita API を呼び出す非同期関数searchQiita()
を実装していきましょう。
今回は先に作ったsearch_screen.dart
内で処理を呼び出すので、search_screen.dart
にメソッドを追加していきます。
1. 使用するパッケージのインポート
まずは、使用するパッケージをファイルをインストールし、インポートしておきましょう。
flutter pub add http
json 変換で使うconvert
、http 通信で使うhttp
、秘匿化したアクセストークンを取得する為のflutter_dotenv
、そして作成したモデルクラスarticle.dart
をインポートします。
import 'dart:convert';
+ import 'package:http/http.dart' as http;
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:qiita_app/models/article.dart';
2. 関数の定義
次に中の処理は置いておいて、関数の定義だけしておきましょう。
Future<List<Article>> searchQiita(String keyword) async {
// 処理を実装
}
API を呼び出し、その結果を待つ非同期処理になるのでFuture
、そして受け取った結果は複数のArticle
クラスに変換するのでリストに格納し、List<Article>
型にするので、関数の返り値は Future<List<Article>>
型になります。
また検索キーワードをリクエストに含める為、String
型の引数を受け取ります。
非同期関数の為、async
も忘れずに。
3. Uri の作成
次に、API のエンドポイントを指定するためのUri
を作成します。
今回はクエリを含める為、先に紹介したUri.parse()
ではなく、クエリを記述しやすいUri.https()
を使います。
Uri.https
では下記の通り、第一引数に baseUrl
、第二引数に path、第三引数にMap<String,dynamic>
型でクエリパラメータを指定します。
final url = Uri.https('qiita.com', '/api/v2/items', {
'query': 'title:$keyword',
'per_page': '10',
});
タイトルで検索をかける為、query
フィールドにtitle
を指定。記事を 10 件取得する為、per_page
フィールドに10
を指定しています。
4. リクエストの作成
肝となるリクエストの作成です。
dotenv を使ってアクセストークンを取得し、リクエストヘッダーに含めて GET リクエストを送信します。
await
で非同期処理を待ち、http.Response
型のres
に結果を格納します。
// アクセストークンを取得
final String token = dotenv.env['QIITA_ACCESS_TOKEN'] ?? '';
// アクセストークンを含めてリクエストを送信
final http.Response res = await http.get(uri, headers: {
'Authorization': 'Bearer $token',
});
5. ステータスに応じた処理
レスポンスを受け取っても通信が成功したとは限りません。http.Response
に含まれるステータスコードを使って、処理を分岐させましょう。
ステータスコードが 200 で成功した場合のみ、結果をモデルクラスへ変換し、それ以外の場合は空のリストを返します。
if (res.statusCode == 200) {
// モデルクラスへ変換
} else {
return [];
}
6. モデルクラスへの変換
成功した API 通信のレスポンスをモデルクラスへ変換します。
レスポンスは複数の投稿データの配列なので、一度jsonDecode()
を使ってList<dynamic>
型に変換します。
その後、map()
でList<dynamic>
型の配列の中身を1つ1つ factory コンストラクタを使ってArticle
オブジェクトに変換し、toList()
で再度配列に格納し直し返します。
// レスポンスをモデルクラスへ変換
final List<dynamic> body = jsonDecode(res.body);
return body.map((dynamic json) => Article.fromJson(json)).toList();
以上で完成です 🙌
全体のコード
+ import 'dart:convert';
+ import 'package:http/http.dart' as http;
+ import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter/material.dart';
+ import 'package:qiita_search/models/article.dart';
class SearchScreen extends StatefulWidget {
const SearchScreen({super.key});
State<SearchScreen> createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Qiita Search'),
),
body: Container(),
);
}
+ Future<List<Article>> searchQiita(String keyword) async {
+ final uri = Uri.https('qiita.com', '/api/v2/items', {
+ 'query': 'title:$keyword',
+ 'per_page': '10',
+ });
+
+ final String token = dotenv.env['QIITA_ACCESS_TOKEN'] ?? '';
+ final http.Response res = await http.get(uri, headers: {
+ 'Authorization': 'Bearer $token',
+ });
+
+ if (res.statusCode == 200) {
+ // レスポンスをモデルクラスへ変換
+ final List<dynamic> body = jsonDecode(res.body);
+ return body.map((dynamic json) => Article.fromJson(json)).toList();
+ } else {
+ return [];
+ }
+ }
}
まとめ
以上でようやく Qiita API から欲しいデータを取得する処理を実装する事が出来ました。
次章からついに Widget を使った UI 実装に入っていきます。