Featured Image
Software Development

Heroes App — Handle sensitive data, API and JSON serialization in Flutter

If you are keen to know what exactly it goes to build a simple app which displays the result from API call, you have landed at the right place.

This article will guide you on various topics such as

  • How to handle sensitive data like API keys.
  • Make API calls.
  • Best way to JSON serialization.
  • Handle Large JSON data that is sufficient to create the jank user experience.

Let’s first see what actually the complete app looks like.

Complete Heroes App

Design inspiration from here So Let’s get started.

1) How to handle sensitive data like API keys

Suppose you are working on an open source project and you don’t want to let the world know the API keys you have used for making API call, This strategy might help you.

Here you have secrets.json file contains all the keys.

{
  "marvel_public_key": "XYZ_API_KEY",
  "marvel_private_key":"XYZ_API_KEY"
}

Don’ forget to add this file to .gitignore Now create another file named assecretloader.dart which has functions that load the JSON file and create a secret object out of it.

Future<Secret> load() {
  return rootBundle.loadStructuredData<Secret>(this.secretPath,
          (jsonStr) async {
        final secret = Secret.fromJson(json.decode(jsonStr));
        return secret;
      });
}

you can create more functions to retrieve any specific key depending upon your use case.

Finally, here the code that will retrieve the secret object and is ready to be used by our API.

SecretLoader(secretPath: 'assets/json/secrets.json')
    .load()
    .then((Secret s) {
      print("${s.marvelPrivateApiKey} and ${s.marvelPublicApiKey}");
}

This article describes all the details about it.

Also read: Creating a Text Reader Animation Using Flutter

2) Make API calls.

Future<HerosHub> herosHub;
url = "https://gateway.marvel.com:443/v1/public/characters?limit=5&apikey=${s.marvelPublicApiKey}&ts=$ts&hash=$hash";
Future<HerosHub> _fetchData(String url) async {
  var res = await http.get(url);
  var decodedJson = jsonDecode(res.body);
  return HerosHub.fromJson(decodedJson);
}
//Make api call
herosHub = _fetchData(url);

Just this much code is required to make API call and here we have desired herosHub object that used to represent API response after JSON serialization and that brings us to next point.

3) JSON serialization

There are two main ways to perform JSON serialization.

  • Manual serialization
  • Automated serialization using code generation

Manual serializations take more time to write code by hand and may produce some errors and most probably typo errors so, in this project, Automated serialization is used to simplify our life. so let’s see how actually it is done.

The first step is to add the required libraries to pubspec.yaml.

dependencies:
  # Your other regular dependencies here
  json_annotation: ^2.0.0
dev_dependencies:
  # Your other dev_dependencies here
  build_runner: ^1.0.0
  json_serializable: ^2.0.0

and model class is updated to generate automatic JSON parsing code such as

heroshub.dart 
import 'package:json_annotation/json_annotation.dart';
part 'heroshub.g.dart';
@JsonSerializable()
class HerosHub {
  HerosHub(this.code, this.status,this.data);
  int code;
  String status;
  Data data;
  factory HerosHub.fromJson(Map<String, dynamic> json) => _$HerosHubFromJson(json);
  Map<String, dynamic> toJson() => _$HerosHubToJson(this);
}

Hit this command in terminal

flutter packages pub run build_runner watch

On successful completion of the above command, heroshub.g.dart file will be created and contain necessary code for JSON parsing.

Also read: Building a Superhero Interaction App with Core Animations in Flutter

4) Handle Large JSON data that is sufficient to create the jank user experience.

You might be knowing that Flutter runs on Dart but you should also know that Dart is Single Threaded. Sometimes you may need to perform heavy lifting such as parsing large JSON or downloading photos then, In that case, you should assign this job to isolates.

Basically, Any work that takes more than 16ms, Use Isolates.

In our case parsing JSON is definitely going to get more than 16ms since we have a lot of characters data to parse. We can modify the code to adopt isolates as such.

Future<HerosHub> _fetchData(String url) async {
  var response = await http.get(url);
  // Now Use the compute function if parsing takes more than 16ms using seperate isolates
  return compute(parseHeros, response.body);
}
// A function that will convert a response body into a HeroHub
HerosHub parseHeros(String responseBody) {
  var decodedJson = jsonDecode(responseBody);
  return HerosHub.fromJson(decodedJson);
}

compute function will take input as data to parse and function that is actually going to parse data.

That’s it.

I hope you have understood the basics of building the simple Flutter app.

Clone it. Play with it. You can get the code here.

If you liked reading this blog, then also read the post on Options to Animate in Flutter.

author
Pinkesh Darji
I love to solve problems using technology that improves user’s life on a major scale. Over the last several years, I have been developing and leading various mobile apps in different areas. More than just programming, I love to write technical articles. I have written many high-quality technical articles. I have worked with various startups to build their dream app. I have been involved in product development since my early days and know insights into it. I have provided my valuable input while taking some crucial decisions of the app by brainstorming with a design, QA team. Over the last 3 years, I have been developing mobile apps and libraries using Google’s Flutter framework. I mentor junior Flutter developers and review their code. You will also find me talking on various Flutter topics in local meetups.