Decode Json from Youtube api on Flutter

2,390

Solution 1

Might be bit late to answer the question.

If you want to learn how to parse complex json data use these articles.

1. Parsing JSON in the background - Flutter cookbook

and Parsing complex JSON in Flutter- medium.com by Pooja Bhaumik

FYI - Youtube data api response is in a nested Json format

I used a alternative way, this is not recommended for big applications(I was just playing around with it and this is only for above type json tree)

Use async function to retrieve and parse Json data.

final String dataUrl = "YOUR-JSON-URL";

Future<String> getdet() async {

var response = await http.get(Uri.encodeFull(dataUrl), headers: {"Accept": "application/json"});

    if (response.statusCode == 200) {
      var responseBody = json.decode(response.body);

      convertedData = responseBody["items"];

    } else {
      throw Exception('Failed to Load Data');
    }

"items " is the array starting point

after that you can use it in a Widget for example

Widget recentWidget(){
    return ListView.builder(
              itemCount: convertedData == null ? 0 : recent.length,
              itemBuilder: (BuildContext context, int index, ) {
              return Column(
               children: <Widget>[
                  Card(
                    child: Column(
                      children: <Widget>[
                        new Image.network(recent[index]["snippet"]["thumbnails"]["medium"]["url"]),
                        new ListTile(                         
                            title: new Text(recent[index]["snippet"]["title"]),
                                subtitle: Text("This is Subtitle"),
                             },
                            dense: true,
                          ),
                      ],
                  ),
              )
            ],
          );
        },shrinkWrap: true,
        physics: ClampingScrollPhysics(),
      )
    }

Hope this helps.

Solution 2

What you are trying won't work with Dart, this is not javascript. Dart has very strong type system, which is great. You are trying to assign value to a variable you've defined as String, but the response you have defined a dynamic, so Dart can't validate the value assignment. Also items is array, there is no such key items->snippet.

The correct way to do this is to create model deinitions, which will handle deserialisation and also will provide convenient way of accessing properties you are interested in.

class YoutubeResponse {

  String kind;
  String etag;
  String nextPageToken;

  String regionCode;
  List<Item> items;

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

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

  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);
  }

}

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

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

  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']),
    );
  }
}

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'],
    );
  }
}

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

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

  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'],
    );
  }

}

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

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

  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'],
    );
  }

}

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

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

  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'],
    );
  }

}

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']),
    );
  }
}

Now that we have described the format of the JSON we expect it is very easy to parse it:

YoutubeResponse parsedResponse =
  YoutubeResponse.fromJSON(json.decode(response.body));

You can then access the items via parsedResponse.items, then loop through them and get the title, descriptions etc.

Solution 3

To further the answer by @Shaddy (which works) here is my class that calls the network

    class VideoNetwork {
  static Future<List<Item>> fetchPost() async {
    final response =
        await http.get(<URL for Youtube Videos>);

    if (response.statusCode == 200) {
      // If the call to the server was successful, parse the JSON
      return compute(parseVideos, response.body);
    } else {
      // If that call was not successful, throw an error.
      throw Exception('Failed to load post');
    }
  }

  static List<Item> parseVideos(String responseBody) {
    YoutubeResponse response =
        YoutubeResponse.fromJSON(json.decode(responseBody));

    return response.items.toList();
  }
}
Share:
2,390
Capitan Luzzatto
Author by

Capitan Luzzatto

Updated on December 07, 2022

Comments

  • Capitan Luzzatto
    Capitan Luzzatto over 1 year

    I make a call to Youtube API and get this Json:

         "kind": "youtube#videoListResponse",
     "etag": "\"XI7nbFXulYBIpL0ayR_gDh3eu1k/s7-xmHXpuqQxYzDp_wxhm59K4LE\"",
     "pageInfo": {
      "totalResults": 1,
      "resultsPerPage": 1
     },
     "items": [
      {
       "kind": "youtube#video",
       "etag": "\"XI7nbFXulYBIpL0ayR_gDh3eu1k/pajQ7iBy-7A0V_owifxkw-Kbw-Y\"",
       "id": "7lCDEYXw3mM",
       "snippet": {
        "publishedAt": "2012-06-20T23:12:38.000Z",
        "channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw",
        "title": "Google I/O 101: Q&A On Using Google APIs",
        "description": "Antonio Fuentes speaks to us and takes questions on working with Google APIs and OAuth 2.0.",
        "thumbnails": {
         "default": {
          "url": "https://i.ytimg.com/vi/7lCDEYXw3mM/default.jpg",
          "width": 120,
          "height": 90
         },
         "medium": {
          "url": "https://i.ytimg.com/vi/7lCDEYXw3mM/mqdefault.jpg",
          "width": 320,
          "height": 180
         },
         "high": {
          "url": "https://i.ytimg.com/vi/7lCDEYXw3mM/hqdefault.jpg",
          "width": 480,
          "height": 360
         }
    

    But now I want to parse it and get just 3 nodes:

    1. Title
    2. Description
    3. The url for the default thumbnail

    Indeed I get the Json response and can see it on the logs, but when try to parse it every time it fails.

    This is my code:

    final response = await http.get(
        'https://www.googleapis.com/youtube/v3/videos?id=HEREGOESMYAPIKEY&part=snippet&id=T0Jqdjbed40');
    
    final parsed = json.decode(response.body).cast<Map<String, dynamic>>();
    String title  = parsed['items']['snippet']['title'];
    print(title);
    String description  = parsed['items']['snippet']['description'];
    print(description);
    String thumbnail  = parsed['items']['snippet']['thumbnails']['default']['url'];
    print(thumbnail);
    
  • Capitan Luzzatto
    Capitan Luzzatto over 5 years
    I added your code but it gives me a [VERBOSE-2:shell.cc(188)] Dart Error: Unhandled exception: NoSuchMethodError: The method 'fromJSON' was called on null.
  • Sh1d0w
    Sh1d0w over 5 years
    @CapitanLuzzatto Have you created and imported all models?
  • Capitan Luzzatto
    Capitan Luzzatto over 5 years
    Yes, also I noted that Android Studio didn't recognized the field Id on the Item object and mPageInfo ond YouTubeResponse object.