Chapter 19

  モデルクラスの作成

heyhey1028
heyhey1028
2023.02.28に更新

さてすぐにも UI の実装に入りたいところですが、まず外堀から埋めていきましょう。この章では前項で確認した内容を元にモデルクラスを作成していきます。

全体像

前項で Qiita API を叩いて取得するレスポンスの JSON を確認しましたが、この JSON を元にモデルクラスに変換していきます。

今回は記事自体を表す Article モデルとユーザーを表す User モデルを作成します。

また JSON として受け取った際に、モデルクラスに変換するためのfromJsonという factory コンストラクタも定義しておきます。

前項でも紹介したレスポンスのデータは網羅的ですが、全てを含めると大きくなってしまうので必要なデータだけピックアップし、モデルクラスを定義しましょう。

レスポンスデータ
[
  {
    "rendered_body": "<h1>Example</h1>",
    "body": "# Example",
    "coediting": false,
    "comments_count": 100,
    "created_at": "2000-01-01T00:00:00+00:00",
    "group": {
      "created_at": "2000-01-01T00:00:00+00:00",
      "description": "This group is for developers.",
      "name": "Dev",
      "private": false,
      "updated_at": "2000-01-01T00:00:00+00:00",
      "url_name": "dev"
    },
    "id": "c686397e4a0f4f11683d",
    "likes_count": 100,
    "private": false,
    "reactions_count": 100,
    "stocks_count": 100,
    "tags": [
      {
        "name": "Ruby",
        "versions": ["0.0.1"]
      }
    ],
    "title": "Example title",
    "updated_at": "2000-01-01T00:00:00+00:00",
    "url": "https://qiita.com/Qiita/items/c686397e4a0f4f11683d",
    "user": {
      "description": "Hello, world.",
      "facebook_id": "qiita",
      "followees_count": 100,
      "followers_count": 200,
      "github_login_name": "qiitan",
      "id": "qiita",
      "items_count": 300,
      "linkedin_id": "qiita",
      "location": "Tokyo, Japan",
      "name": "Qiita キータ",
      "organization": "Qiita Inc.",
      "permanent_id": 1,
      "profile_image_url": "https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/88/ccf90b557a406157dbb9d2d7e543dae384dbb561/large.png?1575443439",
      "team_only": false,
      "twitter_screen_name": "qiita",
      "website_url": "https://qiita.com"
    },
    "page_views_count": 100,
    "team_membership": {
      "name": "Qiita キータ"
    }
  }
]

ディレクトリ配置

ファイルを作るディレクトリはお好みですが、今回はlib直下にmodelsというディレクリを作り、モデルクラスのファイルをまとめておきましょう。

lib
├── main.dart
├── models
│   ├── article.dart
│   └── user.dart
└── screens
    └── search_screen.dart

Article モデルクラスの作成

まずは記事を表すArticleクラスを定義していきます。

こちらのデータを元に検索ページのリストを表示するので、そこで表示したい内容をピックアップしましょう。最低限必要なのはtitleuser辺りでしょうか。そのほかはお好みで適宜選択してみてください。今回はlikes_counttagscreated_atを取得します。

...
"title": "Example title", // タイトル
"user": ..., // ユーザー
"likes_count": 100, // いいね数
"tags": ..., // タグ
"created_at": "2000-01-01T00:00:00+00:00", // 作成日時
...

また記事を表示するページでは WebView のパッケージに記事の URL を渡すので、URL も取得しておきましょう。

...
"url": "https://qiita.com/Qiita/items/c686397e4a0f4f11683d",
...

以上を含めてArticleクラスを定義していきます。

article.dart
class Article {
  // コンストラクタ
  Article({
    required this.title,
    required this.user,
    required this.url,
    required this.createdAt,
    this.likesCount = 0,
    this.tags = const [],
  });

  final String title;
  final User user;
  final String url;
  final DateTime createdAt;
  final int likesCount;
  final List<String> tags;
}


title,user,url,createdAtは必ず存在するのでrequiredとしておきます。

またuserは後述するUserクラスを使います。

JSON→Articleクラスへ変換

次に受け取った JSON をArticleクラスに変換するfactoryコンストラクタを定義します。

  factory Article.fromJson(Map<String, dynamic> json) {
    return Article(
      title: json['title'],
      user: User.fromJson(json['user']),
      url: json['url'],
      createdAt: DateTime.parse(json['created_at'].toString()),
      likesCount: json['likes_count'],
      tags: List<String>.from(json['tags'].map((tag) => tag['name'])),
    );
  }

.fromJsonの名前は自由に変えてもらって大丈夫です。

Map<String,dynamic>型の json を受け取り、1つ1つ展開していきます。tagsは名前だけ欲しいのでmapで展開し、名前だけの配列に変換しています。

...
tags: List<String>.from(json['tags'].map((tag) => tag['name'])),
...
コード全体
lib/models/article.dart
import 'package:qiita_search/models/user.dart';

class Article {
  final String title;
  final User user;
  final String url;
  final DateTime createdAt;
  final int likesCount;
  final List<String> tags;

  Article({
    required this.title,
    required this.user,
    required this.url,
    required this.createdAt,
    this.likesCount = 0,
    this.tags = const [],
  });

  factory Article.fromJson(Map<String, dynamic> json) {
    return Article(
      title: json['title'],
      user: User.fromJson(json['user']),
      url: json['url'],
      createdAt: DateTime.parse(json['created_at'].toString()),
      likesCount: json['likes_count'],
      tags: List<String>.from(json['tags'].map((tag) => tag['name'])),
    );
  }
}

User モデルクラスの作成

Userクラスも同様に定義していきましょう。ユーザーに関するデータはレスポンスのuserフィールド以下の部分に格納されています。

user に関するデータ
...
  "user": {
    "description": "Hello, world.",
    "facebook_id": "qiita",
    "followees_count": 100,
    "followers_count": 200,
    "github_login_name": "qiitan",
    "id": "qiita",
    "items_count": 300,
    "linkedin_id": "qiita",
    "location": "Tokyo, Japan",
    "name": "Qiita キータ",
    "organization": "Qiita Inc.",
    "permanent_id": 1,
    "profile_image_url": "https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/88/ccf90b557a406157dbb9d2d7e543dae384dbb561/large.png?1575443439",
    "team_only": false,
    "twitter_screen_name": "qiita",
    "website_url": "https://qiita.com"
  },
...

こちらもお好みですが今回はidprofinle_image_urlを取得しておきましょう。

...
  "id": "qiita",
  "profile_image_url": "https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/88/ccf90b557a406157dbb9d2d7e543dae384dbb561/large.png?1575443439",
...

以上を含めてUserクラスを定義していきます。

user.dart
class User {
  final String id;
  final String profileImageUrl;

  User({
    required this.id,
    required this.profileImageUrl,
  });
}

次にArticleクラス同様に fromJson と名付けた、factory コンストラクタを定義しましょう。

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'],
      profileImageUrl: json['profile_image_url'],
    );
  }
コード全体
lib/models/user.dart
class User {
  final String id;
  final String profileImageUrl;

  User({
    required this.id,
    required this.profileImageUrl,
  });

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'],
      profileImageUrl: json['profile_image_url'],
    );
  }
}

まとめ

以上で API から取得したデータを格納するモデルクラスが出来ました。

次章では、API 通信を行い、データを取得し、今回定義したモデルクラスに格納する処理を実装していきます。