LoginSignup
0
0

More than 1 year has passed since last update.

ニュースアプリを作成する際にjsonのparseが出来なくて、freezedでつまづいていた

Last updated at Posted at 2023-02-26

はじめに

・この記事のテンプレートを、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形式に変換できるとは。

news_root.dart
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);
}

参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0