はじめに
・この記事のテンプレートを、ChatGPTを使用して作成してもらいましたわ。
「いやー執筆がだいぶ楽になりましたね」などと言うが、普段からなかなか記事を書くことはありませんでした。
しかしながら、最近「アウトプット大全」という本を読みまして、早速行動に移しました。
アプリ概要
・News API (ref: https://newsapi.org/) から取得した米国のヘッドラインニュースを表示するアプリケーションです。
・app
・code
使用した主なパッケージ
- dio: ^4.0.6
- flutter_hooks: ^0.18.5+1
- freezed: ^2.3.2
- hooks_riverpod: ^2.1.3
つまづいていたポイント
・アプリをMMVMで作成するという幾つかの記事を参考にコーディングをしていました。
このMMVMにてつまづいていると思っていたのですが、問題はfreezedで書いたModelにありました。
例えば、以下のjson形式のデータをparseするというもの。
{
"status": "ok",
"totalResults": 68,
"articles": [
{
"source": {
"id": "reuters",
"name": "Reuters"
},
"author": null,
"title": "Musk donated around $1.95 billion in Tesla shares last year - Reuters",
"description": "",
"url": "https://www.reuters.com/markets/us/musk-donated-around-195-billion-tesla-shares-last-year-2023-02-15/",
"urlToImage": "",
"publishedAt": "2023-02-15T10:30:00Z",
"content": ""
},
{
"source": {
"id": null,
"name": "CNBC"
},
"author": "Lora Kolodny, John Rosevear",
"title": "Tesla commits to open 7,500 chargers in the U.S. to other electric vehicles by end of 2024 - CNBC",
"description": "",
"url": "https://www.cnbc.com/2023/02/15/tesla-commits-to-open-7500-chargers-in-the-us-to-other-evs.html",
"urlToImage": "",
"publishedAt": "2023-02-15T10:00:01Z",
"content": ""
}
]
}
・[変更前] api_client.dart
class ApiClient {
Future<Map<String, dynamic>> getHeadlineNews(String country, String apiKey) async {
// dioを使用
final dio = Dio();
const baseUrl = 'https://newsapi.org/v2/top-headlines';
// 後からわかったことだが、responseをfinalで受け取ることが悪かった。
final response = await dio.get('$baseUrl?country=$country&apiKey=$apiKey');
if (response.statusCode == 200) {
try {
// 困ったことにjson.decodeすると、printで出力できない。
// status: 200でresponseしたデータは拾えているはず。ならば、受け取るデータの型が悪いと分かる
// print(json.decode(response.data));
return response.data;
} catch (e) {
throw e;
}
} else {
throw ('Request failed with status: ${response.statusCode}');
}
}
}
・[変更後] api_client.dart
class ApiClient {
Future<NewsRoot> getHeadlineNews(String country, String apiKey) async {
final dio = Dio();
const baseUrl = 'https://newsapi.org/v2/top-headlines';
// responseされたデータをResponse型に入れる
Response response =
await dio.get('$baseUrl?country=$country&apiKey=$apiKey');
if (response.statusCode == 200) {
try {
// responseされたデータをjson形式で読み取り、NewsRoot型にConvert
NewsRoot data = NewsRoot.fromJson(response.data);
return data;
} catch (e) {
throw e;
}
} else {
throw ('Request failed with status: ${response.statusCode}');
}
}
}
api_client.dartファイルの変更前と、変更後で型の変更を行っているのだが、ここをずっとDebugしても、jsonのデコードに失敗する。
それもそのはず、その前の段階で、freezedを使用して、Modelを作成した部分に問題が。
freezedの公式ドキュメントに記載されていたが、freezedにて、ListsやMaps, Setsを使用する際には、以下のように@Freezed(makeCollectionsUnmodifiable: false)
を追記しなければならなかった。結構な時間悩んでいたが、こうしただけで、json形式に変換できるとは。
part 'news_root.freezed.dart';
part 'news_root.g.dart';
+ @Freezed(makeCollectionsUnmodifiable: false)
abstract class NewsRoot with _$NewsRoot {
const factory NewsRoot({
String? status,
int? totalResults,
List<NewsArticle>? articles,
}) = _NewsInfo;
factory NewsRoot.fromJson(Map<String, Object?> json) =>
_$NewsRootFromJson(json);
}
参考文献