A month of Flutter: post model and mock data

Now that there is a basic user interface, 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. 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.

[ { "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 to consume JSON in Flutter, but for now I'm going with the simple dart:convert pattern with a Post class.

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. 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, fromMap , that uses an an 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 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 to dev_dependencies .

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.

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

Posts in this series