A month of Flutter: post model and mock data
Tags: flutter, tutorial
Published: 2018-12-10 20:20:33

_Originally posted on [bendyworks.com](https://bendyworks.com/blog/a-month-of-flutter-post-model-and-mock-data)._

Now that there is a [basic user interface](https://bendyworks.com/blog/a-month-of-flutter-a-list-of-posts), I'm going to create some mock data to display in it. The mock data will be stored in a JSON file and will include just the basic fields needed right now: `id`, `createdAt`, `username`, `imageUrl`, and `text`. For `imageUrl` I grabbed some random images from [Unsplash](https://unsplash.com/). `text` is actually empty as I haven't decided what text to use in the mocks yet.

This is a similar format to what you might expect from a JSON API. In the future there will probably be a `User` object and maybe an `Image` object that includes URLs to different sizes, etc.

~~~json
[
  {
    "id": "7d3d8bd1-b9a6-4e1f-8e4e-dca6f4861441",
    "imageUrl": "https://source.unsplash.com/AEVAMhago-s",
    "createdAt": "2018-12-09T15:35:54.006Z",
    "text": "",
    "username": "woodstock"
  }
]
~~~

There are a [number of ways](https://flutter.io/docs/development/data-and-backend/json) to consume JSON in Flutter, but for now I'm going with the simple `dart:convert` pattern with a `Post` class.

~~~dart
class Post {
  const Post({
    @required this.id,
    @required this.username,
    @required this.createdAt,
    @required this.text,
    @required this.imageUrl,
  });

  Post.fromMap(Map<String, dynamic> data)
      : id = data['id'],
        username = data['username'],
        createdAt = DateTime.parse(data['createdAt']),
        text = data['text'],
        imageUrl = data['imageUrl'];

  final String id;
  final String username;
  final DateTime createdAt;
  final String text;
  final String imageUrl;
}
~~~

I'm not a fan of optional values so I [require everything](https://www.dartlang.org/guides/language/language-tour#optional-parameters). This way I don't have to check if a property exists; I just have to check that the property has a value I can work with.

Along with the default constructor I'm also defining a [named constructor](https://www.dartlang.org/guides/language/language-tour#named-constructors), `fromMap`, that uses an an [initializer list](https://www.dartlang.org/guides/language/language-tour#initializer-list). `fromMap` takes in a Map of the raw data and translates it to class variables. Note that the JSON datetime string is being converted to a Dart [`DateTime`](https://api.dartlang.org/stable/dart-core/DateTime-class.html) instance.

One downside of this code is there isn't a defined format for what the raw JSON data contains. For example, if I remove `DateTime.parse` the linter will not complain and there will be a failure at runtime when the `createdAt` string from the data tries to be set to the `DateTime` type property in `Post`. I have not yet found a way to define the key names and value types in a `Map`.

As the data model will change during development, it's important to make sure `Post` continues to work correctly. I will start with a pretty simple test. It loads the first mock data object, instantiates a `Post` instance, and asserts each value is available as expected. This is a plain Dart test (as opposed to a Flutter widget test) so I will have to add the Dart [`test` package](https://pub.dartlang.org/packages/test) to `dev_dependencies`.

~~~dart
group('Post', () {
  test('fromMap', () async {
    final Post post = Post.fromMap(await postData());

    expect(post.id, '7d3d8bd1-b9a6-4e1f-8e4e-dca6f4861441');
    expect(post.username, 'woodstock');
    expect(post.imageUrl, 'https://source.unsplash.com/AEVAMhago-s');
    expect(post.createdAt, DateTime.parse('2018-12-09T15:35:54.006Z'));
    expect(post.text, '');
  });
});
~~~

There is a new helper function, `postData`, that loads the JSON file, parses it, and returns the first object.

~~~dart
dynamic postData() async {
  final dynamic data = await File('../assets/posts.json').readAsString();
  return json.decode(data).first;
}
~~~

I've implemented the mock data in a JSON file instead of creating a List in Dart because that forces me to use the mock data in an asynchronous way. The real data will be async when pulled from Firestore so I am starting with that pattern now.

## Code changes

- [#22 Add JSON file of mock posts](https://github.com/abraham/birb/pull/22)
- [#23 Add Post model](https://github.com/abraham/birb/pull/21)