Skip to content

Article: How to JSON with Flutter#773

Merged
sethladd merged 11 commits intoflutter:masterfrom
roughike:json-tutorial
Feb 7, 2018
Merged

Article: How to JSON with Flutter#773
sethladd merged 11 commits intoflutter:masterfrom
roughike:json-tutorial

Conversation

@roughike
Copy link
Copy Markdown
Contributor

@roughike roughike commented Jan 4, 2018

@googlebot googlebot added the cla: yes Contributor has signed the Contributor License Agreement label Jan 4, 2018
Comment thread json.md Outdated

Next, define some build actions.

#### Defining the build actions
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI – this has been simplified a lot.

See https://github.com/dart-lang/json_serializable/tree/master/example

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! I'll look into it and update this section.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome.

Copy link
Copy Markdown
Contributor Author

@roughike roughike Jan 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to take a quick look into it, and ran into the exact same issue that this reddit user describes in this comment.

This is reproducible on the latest Flutter version, and happens by simply following these steps:

  • create a new Flutter project
  • add the dependencies listed on the json_serializable example README you just linked
  • attempt to get the packages -> a long error message which states that a version ^0.7.0 for build_runner was not found.

Should I create a more detailed issue report, or is this some common issue that can be resolved easily?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're in dependency lock, I'm pretty sure.

I think I have a path to untangle the knot (at least a bit). Follow here: google/json_serializable.dart#95

Comment thread _includes/sidebar.html Outdated
<li><a href="/platform-channels/">Platform-specific code</a></li>
<li><a href="/reading-writing-files/">Read and write files</a></li>
<li><a href="/networking/">Network and HTTP</a></li>
<li><a href="/json">Serializing JSON objects</a></li>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe more simply: "JSON and serialization"

Comment thread json.md Outdated
permalink: /json/
---

It is hard to think of a mobile app that doesn't need to communicate with a web server at some point. When making network-connected apps, chances are that we need to consume some good old JSON, sooner or later.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

global: please line break at 80 chars

Comment thread json.md Outdated

It is hard to think of a mobile app that doesn't need to communicate with a web server at some point. When making network-connected apps, chances are that we need to consume some good old JSON, sooner or later.

In this tutorial, we look into ways of doing JSON with Flutter. We will go over what JSON solution to use in different scenarios and why.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/doing/using

Comment thread json.md Outdated

Where the manual serialization does not perform well is when your project becomes bigger. Writing the serialization logic by hand can become hard to manage and error-prone. If you have a typo when accessing an unexisting JSON field, your code throws an error during runtime.

If you do not have many JSON models in your project and are looking to test a concept quickly, manual serialization might be the way you want to start.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

link down to the example section. For example: "To learn more, and to see an example, jump to ___________"

(global comment, link to each example from these intro paragraphs)

Comment thread json.md
You might want to use generated code for JSON serialization when you have a medium or a larger project.

## Is there a GSON/Jackson/Moshi equivalent in Flutter?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answer the question immediately, and then provide the background :)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's hard to tell: yes, or no

Comment thread json.md Outdated

Dart has supported _tree shaking_ for quite a long time. With tree shaking, we can “shake off” unused code from our release builds. Tree shaking allows us to optimize the size of our applications significantly.

While Dart users might have gotten used to [dartson](https://pub.dartlang.org/packages/dartson) to (de)serialize their JSON, it does not work with Flutter. The reason behind this is that `dartson`, like [GSON](https://github.com/google/gson) in Java, uses _runtime reflection_. In Flutter, reflection (also known as `dart:mirrors`) is disabled.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might make this paragraph more of an aside. It's probably not relevant to most users. Can you make it an aside, and get to one sentence? e.g. "What about dartson? ____________"

Comment thread json.md Outdated

## Serializing JSON manually using dart:convert

Basic JSON serialization in Flutter is very simple. Dart comes with the `dart:convert` library built in, and using the JSON decoder API is straightforward.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"comes with" and "built in" are redundant

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe: "Flutter has a built-in 'dart:convert' library, which includes a straightforward JSON encoder and decoder."

Comment thread json.md Outdated

Basic JSON serialization in Flutter is very simple. Dart comes with the `dart:convert` library built in, and using the JSON decoder API is straightforward.

Let's say we need to deserialize a JSON representing a user object. For sample purposes, we have a real simple JSON model.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Here is an example JSON for a simple user." to replace the second paragraph

Comment thread json.md
String name;
String email;

User.fromJson(Map<String, dynamic> json)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we not put the constructors together?

Comment thread json.md Outdated
class User {
User(this.name, this.email);

String name;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's make these final

Comment thread json.md Outdated

```dart
Map map = JSON.decode(json);
User user = new User.fromJson(map);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/User user/var user (since it's obvious

Comment thread json.md Outdated
Now the calling code does not have to care about the serialization logic. With this new approach, we can deserialize a user quite easily.

```dart
Map map = JSON.decode(json);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a better variable name for map ?

Comment thread json.md Outdated
String json = JSON.encode(user.toJson());
```

While with this new approach the calling code does not have to worry about JSON serialization at all, the model class still definitely has. In a production app, we would want to be sure that the serialization works. In practice, this means that the `User.fromJson` and `User.toJson` both need to have unit tests in place to verify correct behavior.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this first sentence was hard to parse.

Comment thread json.md Outdated

The `json_serializable` package is an automated source code generator that can generate the JSON serializing boilerplate for us.

Since the serialization code is not handwritten and maintained by us anymore, we minimize the risk of having JSON serialization exceptions at runtime. If the sources are generated, and the app compiles, we should be fine.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this second sentence is redundant.

@sethladd
Copy link
Copy Markdown
Contributor

sethladd commented Jan 8, 2018

Fantastic! Thank you so much.

@roughike
Copy link
Copy Markdown
Contributor Author

roughike commented Jan 9, 2018

Incorporated the first feedback round.

Waiting for @kevmoo to resolve google/json_serializable.dart#95. Once I can test the simplified way of using json_serializable, I'll update the article and ping @kevmoo for a review :)

@roughike roughike changed the title [WIP][General review only] - Article: How to JSON with Flutter [WIP] - Article: How to JSON with Flutter Jan 9, 2018
Comment thread json.md Outdated
}
```

We can run the watcher by doing `dart tool/watch.dart` in our project's root
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/doing/running

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As @kevmoo said in this comment, seems like these sections are going away completely. With the new simplified version of json_serializable, there's no need for manually configuring build actions, watchers and build files. Correct me if I'm wrong.

So, should I:

It's your call @sethladd. I'm fine with either way!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if google/json_serializable.dart#95 is less than a week away, then let's wait.

If it's more than a week, let's publish this article now, as long as you're OK with updating it "soon".

@kevmoo what's the ETA?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As of Flutter latest, everything seems to work – flutter/flutter@6e38b42

It's all about the very tight dependency constraints on packages in flutter & flutter_test

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure we'll want to delay the new documentation until that change is rolled to the alpha branch, which most people are using by default?

(BTW, I have not abandoned this. I would love to do as many feedback rounds as it takes to publish the article, but I'm very busy this week.)

Comment thread json.md Outdated
```

We can run the watcher by doing `dart tool/watch.dart` in our project's root
folder. It is safe to start the watcher once and leave it running in the
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please provide an example of how to run this. (it's not obvious how to use the command-line Dart VM that is bundled with Flutter.)

Comment thread json.md Outdated
```

Now we can generate all the necessary JSON serialization source files by running
`dart tool/build.dart` in our project's root folder. While the build file is all
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this assumes you have the Dart SDK installed separately from Flutter. Instead, please show how to run the command-line Dart VM that is shipped with the flutter SDK.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Hixie
Copy link
Copy Markdown
Contributor

Hixie commented Jan 19, 2018

Just for my own purposes (to make it easier to see what's going on when I go through all the open PRs):

BTW, thanks for your contributions @roughike ! Much appreciated.

@Hixie
Copy link
Copy Markdown
Contributor

Hixie commented Jan 30, 2018

This should be unblocked now, we just rolled dev.

@roughike
Copy link
Copy Markdown
Contributor Author

Great! I'm getting back to Finland in 12hours or so, I'll finish the changes once I wake up and recover from the jet lag. I'll do the "what if I decode lots of JSON and the UI lags" part as well.

@kevmoo
Copy link
Copy Markdown
Contributor

kevmoo commented Jan 30, 2018 via email

@roughike
Copy link
Copy Markdown
Contributor Author

roughike commented Feb 1, 2018

Here's what I found about the "avoiding blocking the UI when decoding lots of JSON" that we discussed in the afterparty:

  • a huge amount of JSON objects (really!) is required to produce any noticeable UI lag
  • when lifting the deserialization to an Isolate spawned by the compute function, UI doesn't lag. But this takes noticeably longer.

I guess the culprit could be passing a huge string (raw JSON) to the Isolate spawned by the compute() function, combined with the overhead of spawning a new Isolate.

See the sample project here.

@roughike
Copy link
Copy Markdown
Contributor Author

roughike commented Feb 1, 2018

I'm pretty sure no one would request 15 000 objects from a backend API at once, but they would implement paging instead.

Given my findings, should we still do the section about the "not blocking UI when deserializing"? I'm completely fine either way :)

@roughike roughike changed the title [WIP] - Article: How to JSON with Flutter Article: How to JSON with Flutter Feb 2, 2018
Comment thread json.md Outdated
---

It is hard to think of a mobile app that doesn't need to communicate with a web
server at some point. When making network-connected apps, the chances are that
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

server, or easily store structured data, at some point

Comment thread json.md Outdated

## Which JSON serialization method is right for me?

There isn't a one size fits all JSON solution for every project.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a short paragraph here:

This article covers two general strategies for working with JSON:

  • Manual serialization and deserialization
  • Automated serialization and deserialization via code generation

Comment thread json.md Outdated
us. Luckily, there is!

<a name="code-generation"></a>
## Serializing JSON using json_serializable
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mention: code generation here (as we talk about it above as "code generation" and that's more what people are looking for. They don't know what json_serializable is , at this point)

For example: serializing JSON using code generation

Copy link
Copy Markdown
Contributor

@sethladd sethladd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, looks great!

A couple of small comments.

Lets address the small comments, merge this article. And then lets add a new section called "working with JSON on another thread"

Thoughts?

@sethladd
Copy link
Copy Markdown
Contributor

sethladd commented Feb 6, 2018

cc @kevmoo to double-check the json_serializable bits of the article. we're about to commit.

@roughike
Copy link
Copy Markdown
Contributor Author

roughike commented Feb 7, 2018

Latest feedback addressed.

let's address the small comments, merge this article. And then let's add a new section called "working with JSON on another thread"

Agreed.

I was thinking of including that new section with this PR, but let's ship this as soon as this is ready. This has already been sitting one month, sorry about that :)

I'll write about that "working with JSON on another thread" in a separate PR.

@roughike
Copy link
Copy Markdown
Contributor Author

roughike commented Feb 7, 2018

Hey @sethladd and @kevmoo, would it make sense to ship a live template with the Flutter / Dart plugin to make using json_serializable even easier?

Something like this:

json_serializable live template

An even crazier idea would be having a squiggly red line under the class name saying "Code not generated yet". By pressing Alt-Enter, an option saying "Generate code for json_serializable model" would appear.

By hitting enter, the following steps would be done:

  • Check if the json_serializable package is declared in pubspec file. If not, add it automatically and refresh the dependencies.
  • Run flutter packages pub run build_runner build for the user to build the generated code.

From the user point of view, all they had to do was write "json", press enter, press Alt-Enter and now they have working json_serializable setup in their model class.

@sethladd
Copy link
Copy Markdown
Contributor

sethladd commented Feb 7, 2018

@roughike that's really cool! I encourage you to open a new issue for that feature request. That way, we can think about how to do it for both VS Code and Android Studio.

@sethladd
Copy link
Copy Markdown
Contributor

sethladd commented Feb 7, 2018

Other than that, thank you! LGTM from me.

Pending LGTM from @kevmoo

@roughike
Copy link
Copy Markdown
Contributor Author

roughike commented Feb 7, 2018

@sethladd What's the correct repo to open that issue? flutter-intellij would be my first guess, but don't know if it's related to Dart analysis server and just disabled on plain Dart projects. :)

Copy link
Copy Markdown
Contributor

@kevmoo kevmoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small tweaks, but otherwise LGTM

Comment thread json.md Outdated

<!-- skip -->
```dart
String json = JSON.encode(user.toJson());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toJson is not needed here. JSON.encode calls toJson for you!

Comment thread json.md Outdated
: name = json['name'],
email = json['email'];

Map<String, dynamic> toJson() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would probably use => notation here.

Map<String, dynamic> toJson() => 
  {
   'name'
...

Copy link
Copy Markdown
Contributor Author

@roughike roughike Feb 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can definitely change it, but the original reasoning for me going the long route was that dartfmt always formats it like this:

Map<String, dynamic> toJson() => {
      'name': name,
      'email': email,
    };

Which in my eyes didn't look as pretty.

Comment thread json.md Outdated
## Serializing JSON using code generation libraries

Although there are other libraries available, in this tutorial, we use the
[json_serializable package](https://github.com/dart-lang/json_serializable). It
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread json.md Outdated

<!-- skip -->
```dart
String json = JSON.encode(user.toJson());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto about not needing .toJson() here

@kevmoo
Copy link
Copy Markdown
Contributor

kevmoo commented Feb 7, 2018 via email

@sethladd
Copy link
Copy Markdown
Contributor

sethladd commented Feb 7, 2018

@roughike please open the issue here (flutter/flutter/issues) as it is a general request that spans many parts of the system.

Are we ready to merge? Anything else to add , @roughike ?

@roughike
Copy link
Copy Markdown
Contributor Author

roughike commented Feb 7, 2018

I'm ready to merge. I'll create the issue tomorrow and open a new PR about "serializing JSON on a separate thread" when I can!

@sethladd
Copy link
Copy Markdown
Contributor

sethladd commented Feb 7, 2018

Nice, thanks!

@sethladd sethladd merged commit d853586 into flutter:master Feb 7, 2018
@roughike roughike deleted the json-tutorial branch March 5, 2018 11:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla: yes Contributor has signed the Contributor License Agreement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants