How to Parse JSON data in Flutter SDK and showing parsed response in Flutter ListView

In this tutorial we will cover following:

  1. How to make API/Network Calls in Flutter.
  2. How to parse JSON Object in Flutter SDK.
  3. How to parse JSON Array in Flutter SDK.
  4. Mapping JSON into Dart Model classes.
  5. Showing JSON Response into ListView Widget in Flutter.
  6. Consuming Youtube API and parse its JSON Data into Flutter Model Classes.
  7. What is Future Builder in Flutter.
  8. Async and Http Client in Flutter SDK

Nowadays It is very rare for a mobile to work only in offline mode and never communicate with any server and submit or get response from server and show it to app users.

So If your Application needs to communicate with server or needs to consume any third party API you will need to interact with JSON.

Because nowadays JSON (JAVA SCRIPT OBJECT NOTATION) is very common data format.

JSON Serialization and Deserialization Methods:

Typically there are two methods through which you can parse JSON Objects in your application.

  1. Manual JSON Parsing in Flutter

Manually parsing JSON is error prone and time taking task.

Because you have to write code for getting each and every Map<String, dynamic> manually.

And if at run-time any of the key or value is missing in JSON Object your app might crash.

I assume you know JSON Data Format (It is in key value pair, whereas Key is always string and value can be anything. Value can be another JSON Object, JSON Array, String, Float, Double that is why It is dynamic in Flutter).

Required Packages and Dependencies for JSON Parsing and API Calling:

If your app needs to use third party libraries or SDK for example Firebase SDK, http (for network communication) you are required to add packages in your flutter app.

Flutter dependencies or packages adding
Adding Flutter Packages

Please see the highlighted fields, Flutter packages can be added under pubspec.yaml file in your project.

Any package will be under dependencies block like above http package.

After you make any change in pubspec.yaml file or add any new package just click Packages get button on top right (Highligted).

Now are are ready to make network request or API call and Parse JSON.

Basic Pubspec YAML File:
// pubspec.yaml

name: flutter_json_parsing_example
description: Flutter JSON Parsing Example Code DART

version: 1.0.0+1
environment:
  sdk: ">=2.0.0-dev.68.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2
  shrine_images: 1.0.0
  http: ^0.11.3+16

dev_dependencies:
  flutter_test:
    sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec

# The following section is specific to Flutter.
flutter:
  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true
Youtube Search API:

We will be calling Youtube Search API in our Flutter app and will parse its response.

API End Point:

https://www.googleapis.com/youtube/v3/search?q=javascript&maxResults=12&part=snippet&key=AIzaSyCk3nUhQgjVI9zKjMmuNaF6sxCY4

Simply hit this API in your browser and you will get JSON response.

Note: You are supposed to use your own Youtube API Key and replace it with key attribute.

Let’s examine API Response (JSON Object Structure)
Flutter JSON Parsing Example CODE
Parsing Youtube API JSON Response in Flutter

I have selected complex JSON Object for Parsing tutorial so we can cover all use cases related to JSON Parsing in Flutter e.g Serialization, Array Parsing, Nested Objects and all that.

As you can see above JSON Object contains pageInfo Object and items Array and items array contains few other JSON Objects like id and snippet.

Snippet Object further contains Video Title, Video Description and thumbnails.

Lets move to the real part (Coding)

Here we will perform two main functions.

  1. Making HTTP call.
  2. Converting JSON response into Dart Model Classes and Object.

Add a new function searchYoutube():

You need to import Future and http Packages in this class.

import 'package:http/http.dart' as http;
import 'dart:async' show Future;

  
  var apiURL =
      "https://www.googleapis.com/youtube/v3/search?q=Android&maxResults=12
       &part=snippet
       &key=YOUR_YOUTUBE_API_KEY";

  Future<http.Response> searchYoutube() async {
    
    final youtubeResponse = http.Client().get(apiURL);

  }

Lets understand keywords used in above Network Utility class.

Future

Future is a Dart class which is used to work with asynchronus operation. It is used to represent a value or object which will be available at later.

http.Response

http Response will contain Raw data returned from API Call.

Later we will convert/map this response into Dart Model Classes.

http.Client()

Building Http object for making Network Call.

At this stage we are making youtube search api call with ‘Android’ search Query.

And getting http Response object.

But we need to parse http Response object into Dart Model Classes.

Creating Model Classes

Create a new package ‘model’ in your project and create new Dart Class YoutubeResponse.

// YoutubeResponse.dart

import 'pageInfo.dart';
import 'Item.dart';

class YoutubeResponse {

  // Fields and Objects in YoutubeResponse according to JSON Data.

  String kind;
  String etag;
  String nextPageToken;

  String regionCode;
  pageInfo mPageInfo;
  List<Item> items;

 // Constructor

  YoutubeResponse(
      {this.kind,
      this.etag,
      this.nextPageToken,
      this.regionCode,
      this.mPageInfo,
      this.items});

 // toJson() function discussed below.

  Map<String, dynamic> toJson() => {
        'kind': kind,
        'etag': etag,
        'nextPageToken': nextPageToken,
        'regionCode': regionCode,
        'pageInfo': mPageInfo,
        'items': items,
      };

  // fromJSON FUNCTION EXPLAINED BELOW.

  factory YoutubeResponse.fromJSON(Map<String, dynamic> YoutubeResponseJson) {

    var list = YoutubeResponseJson['items'] as List;
    List<Item> itemsList = list.map((i) => Item.fromJSON(i)).toList();

    return new YoutubeResponse(
        kind: YoutubeResponseJson['kind'],
        etag: YoutubeResponseJson['etag'],
        nextPageToken: YoutubeResponseJson['nextPageToken'],
        regionCode: YoutubeResponseJson['regionCode'],
        mPageInfo: pageInfo.fromJSON(YoutubeResponseJson['pageInfo']),
        items: itemsList);
  }

}
Factory method fromJson in Flutter

Above fromJSON function/method starts with ‘factorykeyword.

In our YoutubeResponse.fromJson() function we are just deserializing our JSON Object and returning a new Instance of YoutubeResponse.dart class.

fromJSON Function Arguments

As you can see that fromJson function receives Map<String, dynamic> object.

“Our JSON is always in key value pair”.

In Map object String represents a “key” and dynamic represents value.

Why Dynamic ?

Because objects inside JSON can be of any type (String, Other Custom Objects).

Deserializing child objects Flutter

As you might have noticed that YoutubeResponse contains 4 Strings (Objects in JSON) and 2 Other Model classes (also Objects in returned JSON)

String kind;
String etag;
String nextPageToken;
String regionCode;

Parsing a string object ‘Kind’ is as simple as 

kind: YoutubeResponseJson[‘kind’]

How to get below objects mapping:

pageInfo mPageInfo;        // Parsing child JSON objects in Flutter.
List<Item> items;              // this one is JSON ARRAY.

Parsing JSON Array in Flutter

Please note that below code snippet is from our YoutubeResponseAPI fromJSON function (inside constructor body).

var list = YoutubeResponseJson['items'] as List;
List<Item> itemsList = list.map((i) => Item.fromJSON(i)).toList();

Parsing Child JSON Objects:
mPageInfo: pageInfo.fromJSON(YoutubeResponseJson['pageInfo'])

Lets create rest of the Model Classes.

Copy paste below classes in your project model package.

import 'dart:convert';

class pageInfo {

  int totalResults;
  int resultsPerPage;

  pageInfo({this.totalResults, this.resultsPerPage});


  Map<String, dynamic> toJson() => {
        'totalResults': totalResults,
        'resultsPerPage': resultsPerPage,
      };

  factory pageInfo.fromJSON(Map<String, dynamic> pageInfoJson) {
    return new pageInfo(
      totalResults: pageInfoJson['totalResults'],
      resultsPerPage: pageInfoJson['resultsPerPage'],
    );
  }
}

//////////////////////////////////////////

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'Snippet.dart';
import 'Id.dart';

class Item {
  String kind;
  String etag;
  Id id;
  Snippet snippet;

  Item({this.kind, this.etag, this.id, this.snippet});

  var data = JsonEncoder().convert("");

  Map<String, dynamic> toJson() => {
        'kind': kind,
        'etag': etag,
        'id': id,
        'snippet': snippet,
      };

  factory Item.fromJSON(Map<String, dynamic> ItemJson) {
    return Item(
      kind: ItemJson['kind'],
      etag: ItemJson['etag'],
      id: Id.fromJSON(ItemJson['id']),
      snippet: Snippet.fromJSON(ItemJson['snippet']),
    );
  }
}
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'Thumbnails.dart';

class Snippet {
  String publishedAt;
  String channelId;
  String title;
  String description;
  Thumbnails thumbnails;
  String channelTitle;
  String liveBroadcastContent;

  Snippet(
      {this.publishedAt,
      this.channelId,
      this.title,
      this.description,
      this.thumbnails,
      this.channelTitle,
      this.liveBroadcastContent});


  Map<String, dynamic> toJson() => {
        'publishedAt': publishedAt,
        'channelId': channelId,
        'title': title,
        'description': description,
        'thumbnails': thumbnails,
        'channelTitle': channelTitle,
        'liveBroadcastContent': liveBroadcastContent,
      };

  factory Snippet.fromJSON(Map<String, dynamic> SnippetJson) {


    return Snippet(
      publishedAt: SnippetJson['publishedAt'],
      channelId: SnippetJson['channelId'],
      title: SnippetJson['title'],
      description: SnippetJson['description'],
      thumbnails:  Thumbnails.fromJSON(SnippetJson['thumbnails']) ,
      channelTitle: SnippetJson['channelTitle'],
      liveBroadcastContent: SnippetJson['liveBroadcastContent'],
    );
  }
}
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'Default.dart';
import 'Medium.dart';
import 'High.dart';

class Thumbnails {
  Default mDefault;
  Medium medium;
  High high;

  Thumbnails({this.mDefault, this.medium, this.high});

  var data = JsonEncoder().convert("");

  Map<String, dynamic> toJson() => {
        'default': mDefault,
        'medium': medium,
        'high': high,
      };

  factory Thumbnails.fromJSON(Map<String, dynamic> ThumbnailsJson) {
    return Thumbnails(
      mDefault: Default.fromJSON(ThumbnailsJson['default']),
      medium: Medium.fromJSON(ThumbnailsJson['medium']),
      high: High.fromJSON(ThumbnailsJson['high']),
    );
  }
}
import 'dart:convert';
import 'package:http/http.dart' as http;

class Id {
  String kind;
  String videoId;

  Id({this.kind, this.videoId});

  var data = JsonEncoder().convert("");

  Map<String, dynamic> toJson() => {
        'kind': kind,
        'videoId': videoId,
      };

  factory Id.fromJSON(Map<String, dynamic> defaultJson) {
    return Id(
      kind: defaultJson['kind'],
      videoId: defaultJson['videoId'],
    );
  }

}
import 'dart:convert';
import 'package:http/http.dart' as http;

class Medium {
  int height;
  int width;
  String url;

  Medium({this.height, this.width, this.url});

  var data = JsonEncoder().convert("");

  Map<String, dynamic> toJson() => {
        'height': height,
        'width': width,
        'url': url,
      };

  factory Medium.fromJSON(Map<String, dynamic> MediumJson) {
    return Medium(
      height: MediumJson['height'],
      width: MediumJson['width'],
      url: MediumJson['url'],
    );
  }

}
import 'dart:convert';
import 'package:http/http.dart' as http;

class High {
  int height;
  int width;
  String url;

  High({this.height, this.width, this.url});

  var data = JsonEncoder().convert("");

  Map<String, dynamic> toJson() => {
        'height': height,
        'width': width,
        'url': url,
      };

  factory High.fromJSON(Map<String, dynamic> HighJson) {
    return High(
      height: HighJson['height'],
      width: HighJson['width'],
      url: HighJson['url'],
    );
  }

}
import 'dart:convert';
import 'package:http/http.dart' as http;

class Default {
  int height;
  int width;
  String url;

  Default({this.height, this.width, this.url});

  var data = JsonEncoder().convert("");

  Map<String, dynamic> toJson() => {
        'height': height,
        'width': width,
        'url': url,
      };

  factory Default.fromJSON(Map<String, dynamic> defaultJson) {
    return Default(
      height: defaultJson['height'],
      width: defaultJson['width'],
      url: defaultJson['url'],
    );
  }

}

please make sure you have created 9 Model classes.

Making API Call and Displaying Data on UI
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:async' show Future;
import 'model/YoutubeResponse.dart';
import 'dart:convert';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: new AppBar(
          title: new Text('Flutter Demo App JSON Parsing'),
        ),
        body: Center(
          child: FutureBuilder<YoutubeResponse>(
            future: searchYoutubeAPI(),
            builder: (context, snapshot) {
              return Text(snapshot.data.etag);
            },
          ),
        ),
      ),
    );
  }
}

Complete Code:

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:async' show Future;
import 'model/YoutubeResponse.dart';
import 'dart:convert';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: new AppBar(
          title: new Text('Flutter Demo App JSON Parsing'),
        ),
        body: Center(
          child: FutureBuilder<YoutubeResponse>(
            future: searchYoutubeAPI(),
            builder: (context, snapshot) {
              return Text(snapshot.data.etag);
            },
          ),
        ),
      ),
    );
  }
}

var apiURL =
    "https://www.googleapis.com/youtube/v3/search?q=Android&maxResults=12&part=snippet&key=YOUR_API_KEY";

Future<YoutubeResponse> searchYoutubeAPI() async {
  var youtubeResponse = await http.Client().get(apiURL);

  var parsedResponse =
      YoutubeResponse.fromJSON(json.decode(youtubeResponse.body));

  return parsedResponse;

  print(" Youtube JSON PARSING LOG: " + parsedResponse.items[0].data);
}

copyright: http://developine.com/

Contact Us