Search code examples
jsondartflutterfuturegoogle-books

Flutter parsing Google Books API


I am trying to use the google books API in a new flutter app and am having a lot of trouble parsing the json into a useable format. I am new to coding and flutter and have used the following article to try and learn how to parse the json: https://medium.com/flutter-community/parsing-complex-json-in-flutter-747c46655f51

My code is likely completely incorrect but I would appreciate some help in figuring this out. The objective is to get a list of books where I can have a card for each with the book details. I am fine with the creation of the UI, it's just the json I am struggling with.

My code for the classes to apply the json to:

class Volume {
  List<VolumeInfo> topLevelRelated;

  Volume({this.topLevelRelated});

  factory Volume.fromJson(Map<String, dynamic> parsedJson) {
    var list = parsedJson['items'] as List;
    List<VolumeInfo> volumeList =
        list.map((i) => VolumeInfo.fromJson(i)).toList();
    return Volume(topLevelRelated: volumeList);
  }
}

class VolumeInfo {
  RelatedBook relatedTitles;

  VolumeInfo({this.relatedTitles});

  factory VolumeInfo.fromJson(Map<String, dynamic> parsedJson) {
    return VolumeInfo(
        relatedTitles: RelatedBook.fromJson(parsedJson['volumeinfo']));
  }
}

class RelatedBook {
  String title;
  List<String> authors;
  ImageLinks imagelink;
  List<IndustryIds> iSBN13;
  String printType;

  RelatedBook(
      {this.authors, this.imagelink, this.iSBN13, this.printType, this.title});

  factory RelatedBook.fromJson(Map<String, dynamic> parsedJson) {
    //this is to get ISBNs for related books
    var list = parsedJson['industryIdentifiers'] as List;
    List<IndustryIds> idList =
        list.map((i) => IndustryIds.fromJson(i)).toList();
    //end of ISBN list code

    //authors to a list code
    var authorsFromJson = parsedJson['authors'];
    List<String> authorsList = new List<String>.from(authorsFromJson);
    //end of authors code

    return RelatedBook(
        iSBN13: idList,
        title: parsedJson['title'],
        authors: authorsList,
        printType: parsedJson['printType'],
        imagelink: ImageLinks.fromJson(parsedJson['imageLinks']));
  }
}

class ImageLinks {
  String smallthumb;
  String bigthumb;

  ImageLinks({this.bigthumb, this.smallthumb});

  factory ImageLinks.fromJson(Map<String, String> parsedJson) {
    return ImageLinks(
        bigthumb: parsedJson['thumbnail'],
        smallthumb: parsedJson['smallThumbnail']);
  }
}

class IndustryIds {
  String identifier;
  String type;

  IndustryIds({this.type, this.identifier});

  factory IndustryIds.fromJson(Map<String, dynamic> parsedJson) {
    return IndustryIds(
        type: parsedJson['type'], identifier: parsedJson['identifier']);
  }
}

class Authors {
  List<String> author;

  Authors({this.author});

  factory Authors.fromJson(Map<String, dynamic> parsedJson) {
    return Authors(author: parsedJson['authors']);
  }
}

and my code for the api call and converting this to a useable object:

Future<List<Volume>> getRelateds() async {

    final jsonResponse = await http.get(
        'https://www.googleapis.com/books/v1/volumes?q=${isbn}&maxResults=3');

    Volume otherBook1 = Volume.fromJson(json.decode(jsonResponse.body));

    print(otherBook1);
    return Volume;
  }

Apologies for the terrible code, any help is much appreciated.

Example json repsonse:

{
    "kind": "books#volumes",
    "totalItems": 644,
    "items": [
        {
            "kind": "books#volume",
            "id": "zEzVjgEACAAJ",
            "etag": "Rgo2+5tbv7o",
            "selfLink": "https://www.googleapis.com/books/v1/volumes/zEzVjgEACAAJ",
            "volumeInfo": {
                "title": "Austral",
                "authors": [
                    "Paul McAuley"
                ],
                "publisher": "Gollancz",
                "publishedDate": "2018-10-09",
                "description": "The great geoengineering projects have failed. The world is still warming, sea levels are still rising, and the Antarctic Peninsula is home to Earth's newest nation, with life quickened by ecopoets spreading across valleys and fjords exposed by the retreat of the ice. Austral Morales Ferrado, a child of the last generation of ecopoets, is a husky: an edited person adapted to the unforgiving climate of the far south, feared and despised by most of its population. She's been a convict, a corrections officer in a labour camp, and consort to a criminal, and now, out of desperation, she has committed the kidnapping of the century. But before she can collect the ransom and make a new life elsewhere, she must find a place of safety amongst the peninsula's forests and icy plateaus, and evade a criminal gang that has its own plans for the teenage girl she's taken hostage. Blending the story of Austral's flight with the fractured history of her family and its role in the colonisation of Antarctica, Austral is a vivid portrayal of a treacherous new world created by climate change, and shaped by the betrayals and mistakes of the past. 'Paul McAuley's balanced grasp of science and literature, always a rare attribute in the writer of prose fiction, is combined with the equally rare ability to look at today's problems and know which are really problems, and what can be done about them.' William Gibson",
                "industryIdentifiers": [
                    {
                        "type": "ISBN_10",
                        "identifier": "1473217326"
                    },
                    {
                        "type": "ISBN_13",
                        "identifier": "9781473217324"
                    }
                ],
                "readingModes": {
                    "text": false,
                    "image": false
                },
                "pageCount": 288,
                "printType": "BOOK",
                "categories": [
                    "Fiction"
                ],
                "averageRating": 3,
                "ratingsCount": 1,
                "maturityRating": "NOT_MATURE",
                "allowAnonLogging": false,
                "contentVersion": "preview-1.0.0",
                "panelizationSummary": {
                    "containsEpubBubbles": false,
                    "containsImageBubbles": false
                },
                "imageLinks": {
                    "smallThumbnail": "http://books.google.com/books/content?id=zEzVjgEACAAJ&printsec=frontcover&img=1&zoom=5&source=gbs_api",
                    "thumbnail": "http://books.google.com/books/content?id=zEzVjgEACAAJ&printsec=frontcover&img=1&zoom=1&source=gbs_api"
                },
                "language": "en",
                "previewLink": "http://books.google.co.uk/books?id=zEzVjgEACAAJ&dq=9781473217324&hl=&cd=1&source=gbs_api",
                "infoLink": "http://books.google.co.uk/books?id=zEzVjgEACAAJ&dq=9781473217324&hl=&source=gbs_api",
                "canonicalVolumeLink": "https://books.google.com/books/about/Austral.html?hl=&id=zEzVjgEACAAJ"
            },
            "saleInfo": {
                "country": "GB",
                "saleability": "NOT_FOR_SALE",
                "isEbook": false
            },
            "accessInfo": {
                "country": "GB",
                "viewability": "NO_PAGES",
                "embeddable": false,
                "publicDomain": false,
                "textToSpeechPermission": "ALLOWED",
                "epub": {
                    "isAvailable": false
                },
                "pdf": {
                    "isAvailable": false
                },
                "webReaderLink": "http://play.google.com/books/reader?id=zEzVjgEACAAJ&hl=&printsec=frontcover&source=gbs_api",
                "accessViewStatus": "NONE",
                "quoteSharingAllowed": false
            },
            "searchInfo": {
                "textSnippet": "Blending the story of Austral&#39;s flight with the fractured history of her family and its role in the colonisation of Antarctica, Austral is a vivid portrayal of a treacherous new world created by climate change, and shaped by the betrayals ..."
            }
        },
        {
            "kind": "books#volume",
            "id": "biKbAAAACAAJ",
            "etag": "2OgHBM7bBgk",
            "selfLink": "https://www.googleapis.com/books/v1/volumes/biKbAAAACAAJ",
            "volumeInfo": {
                "title": "Four Hundred Billion Stars",
                "authors": [
                    "Paul J. McAuley"
                ],
                "publisher": "Del Rey Books",
                "publishedDate": "1988",
                "description": "Dorothy Yoshida, an astronomer and telepath, joins the archaelogical team exploring the mysterious ruins of a nearly dead planet that shows some signs of returning to life",
                "industryIdentifiers": [
                    {
                        "type": "ISBN_10",
                        "identifier": "0345351754"
                    },
                    {
                        "type": "ISBN_13",
                        "identifier": "9780345351753"
                    }
                ],
                "readingModes": {
                    "text": false,
                    "image": false
                },
                "pageCount": 282,
                "printType": "BOOK",
                "categories": [
                    "Fiction"
                ],
                "maturityRating": "NOT_MATURE",
                "allowAnonLogging": false,
                "contentVersion": "preview-1.0.0",
                "language": "en",
                "previewLink": "http://books.google.co.uk/books?id=biKbAAAACAAJ&dq=9781473217324&hl=&cd=2&source=gbs_api",
                "infoLink": "http://books.google.co.uk/books?id=biKbAAAACAAJ&dq=9781473217324&hl=&source=gbs_api",
                "canonicalVolumeLink": "https://books.google.com/books/about/Four_Hundred_Billion_Stars.html?hl=&id=biKbAAAACAAJ"
            },
            "saleInfo": {
                "country": "GB",
                "saleability": "NOT_FOR_SALE",
                "isEbook": false
            },
            "accessInfo": {
                "country": "GB",
                "viewability": "NO_PAGES",
                "embeddable": false,
                "publicDomain": false,
                "textToSpeechPermission": "ALLOWED",
                "epub": {
                    "isAvailable": false
                },
                "pdf": {
                    "isAvailable": false
                },
                "webReaderLink": "http://play.google.com/books/reader?id=biKbAAAACAAJ&hl=&printsec=frontcover&source=gbs_api",
                "accessViewStatus": "NONE",
                "quoteSharingAllowed": false
            },
            "searchInfo": {
                "textSnippet": "Dorothy Yoshida, an astronomer and telepath, joins the archaelogical team exploring the mysterious ruins of a nearly dead planet that shows some signs of returning to life"
            }
        },
        {
            "kind": "books#volume",
            "id": "Z7x9BAAAQBAJ",
            "etag": "Qy9xvTfprmo",
            "selfLink": "https://www.googleapis.com/books/v1/volumes/Z7x9BAAAQBAJ",
            "volumeInfo": {
                "title": "Something Coming Through",
                "authors": [
                    "Paul McAuley"
                ],
                "publisher": "Hachette UK",
                "publishedDate": "2015-02-19",
                "description": "The aliens are here. And they want to help. The extraordinary new project from one of the country's most acclaimed and consistently brilliant SF novelists of the last 30 years. The Jackaroo have given humanity fifteen worlds and the means to reach them. They're a chance to start over, but they're also littered with ruins and artifacts left by the Jackaroo's previous clients. Miracles that could reverse the damage caused by war, climate change, and rising sea levels. Nightmares that could forever alter humanity - or even destroy it. Chloe Millar works in London, mapping changes caused by imported scraps of alien technology. When she stumbles across a pair of orphaned kids possessed by an ancient ghost, she must decide whether to help them or to hand them over to the authorities. Authorities who believe that their visions point towards a new kind of danger. And on one of the Jackaroo's gift-worlds, the murder of a man who has just arrived from Earth leads policeman Vic Gayle to a war between rival gangs over possession of a remote excavation site. Something is coming through. Something linked to the visions of Chloe's orphans, and Vic Gayle's murder investigation. Something that will challenge the limits of the Jackaroo's benevolence ...",
                "industryIdentifiers": [
                    {
                        "type": "ISBN_13",
                        "identifier": "9781473203969"
                    },
                    {
                        "type": "ISBN_10",
                        "identifier": "1473203961"
                    }
                ],
                "readingModes": {
                    "text": true,
                    "image": false
                },
                "pageCount": 320,
                "printType": "BOOK",
                "categories": [
                    "Fiction"
                ],
                "averageRating": 3.5,
                "ratingsCount": 2,
                "maturityRating": "NOT_MATURE",
                "allowAnonLogging": true,
                "contentVersion": "1.8.7.0.preview.2",
                "panelizationSummary": {
                    "containsEpubBubbles": false,
                    "containsImageBubbles": false
                },
                "imageLinks": {
                    "smallThumbnail": "http://books.google.com/books/content?id=Z7x9BAAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api",
                    "thumbnail": "http://books.google.com/books/content?id=Z7x9BAAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
                },
                "language": "en",
                "previewLink": "http://books.google.co.uk/books?id=Z7x9BAAAQBAJ&printsec=frontcover&dq=9781473217324&hl=&cd=3&source=gbs_api",
                "infoLink": "https://play.google.com/store/books/details?id=Z7x9BAAAQBAJ&source=gbs_api",
                "canonicalVolumeLink": "https://market.android.com/details?id=book-Z7x9BAAAQBAJ"
            },
            "saleInfo": {
                "country": "GB",
                "saleability": "FOR_SALE",
                "isEbook": true,
                "listPrice": {
                    "amount": 3.99,
                    "currencyCode": "GBP"
                },
                "retailPrice": {
                    "amount": 3.99,
                    "currencyCode": "GBP"
                },
                "buyLink": "https://play.google.com/store/books/details?id=Z7x9BAAAQBAJ&rdid=book-Z7x9BAAAQBAJ&rdot=1&source=gbs_api",
                "offers": [
                    {
                        "finskyOfferType": 1,
                        "listPrice": {
                            "amountInMicros": 3990000,
                            "currencyCode": "GBP"
                        },
                        "retailPrice": {
                            "amountInMicros": 3990000,
                            "currencyCode": "GBP"
                        },
                        "giftable": true
                    }
                ]
            },
            "accessInfo": {
                "country": "GB",
                "viewability": "PARTIAL",
                "embeddable": true,
                "publicDomain": false,
                "textToSpeechPermission": "ALLOWED_FOR_ACCESSIBILITY",
                "epub": {
                    "isAvailable": true,
                    "acsTokenLink": "http://books.google.co.uk/books/download/Something_Coming_Through-sample-epub.acsm?id=Z7x9BAAAQBAJ&format=epub&output=acs4_fulfillment_token&dl_type=sample&source=gbs_api"
                },
                "pdf": {
                    "isAvailable": false
                },
                "webReaderLink": "http://play.google.com/books/reader?id=Z7x9BAAAQBAJ&hl=&printsec=frontcover&source=gbs_api",
                "accessViewStatus": "SAMPLE",
                "quoteSharingAllowed": false
            },
            "searchInfo": {
                "textSnippet": "And on one of the Jackaroo&#39;s gift-worlds, the murder of a man who has just arrived from Earth leads policeman Vic Gayle to a war between rival gangs over possession of a remote excavation site. Something is coming through."
            }
        }
    ]
}

Solution

  • I have resolved this with the following code:

    class VolumeJson {
      final int totalItems;
    
      final String kind;
    
      final List<Item> items;
    
      VolumeJson({this.items, this.kind, this.totalItems});
    
      factory VolumeJson.fromJson(Map<String, dynamic> parsedJson) {
        var list = parsedJson['items'] as List;
    
        List<Item> itemList = list.map((i) => Item.fromJson(i)).toList();
        print(itemList.length);
    
        return VolumeJson(
            items: itemList,
            kind: parsedJson['kind'],
            totalItems: parsedJson['totalItems']);
      }
    }
    
    class Item {
      final String kind;
    
      final String etag;
    
      final VolumeInfo volumeinfo;
    
      Item({this.kind, this.etag, this.volumeinfo});
    
      factory Item.fromJson(Map<String, dynamic> parsedJson) {
        return Item(
            kind: parsedJson['kind'],
            etag: parsedJson['etag'],
            volumeinfo: VolumeInfo.fromJson(parsedJson['volumeInfo']));
      }
    }
    
    class VolumeInfo {
      final String title;
    
      final String publisher;
    
      final String printType;
    
      final ImageLinks image;
    
    
    
      VolumeInfo(
          {this.printType, this.title, this.publisher, this.image, });
    
      factory VolumeInfo.fromJson(Map<String, dynamic> parsedJson) {
    
        print('GETTING DATA');
        //print(isbnList[1]);
        return VolumeInfo(
          title: parsedJson['title'],
          publisher: parsedJson['publisher'],
          printType: parsedJson['printType'],
          image: ImageLinks.fromJson(
            parsedJson['imageLinks'],
          ),
    
        );
      }
    }
    
    class ImageLinks {
      final String thumb;
    
      ImageLinks({this.thumb});
    
      factory ImageLinks.fromJson(Map<String, dynamic> parsedJson) {
        return ImageLinks(thumb: parsedJson['thumbnail']);
      }
    }
    
    class ISBN {
      final String iSBN13;
      final String type;
    
      ISBN({this.iSBN13, this.type});
    
      factory ISBN.fromJson(Map<String, dynamic> parsedJson) {
        return ISBN(
          iSBN13: parsedJson['identifier'],
          type: parsedJson['type'],
        );
      }
    }
    

    And layout and use of the class:

    Column(
                  mainAxisSize: MainAxisSize.min,
                  // crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    Flexible(
                      fit: FlexFit.loose,
                      child: Container(
                          margin: EdgeInsets.all(2.0),
                          child: Column(
                            mainAxisAlignment: MainAxisAlignment.start,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            mainAxisSize: MainAxisSize.min,
                            children: <Widget>[
                              Container(
                                  margin: EdgeInsets.only(
                                    bottom: 3.0,
                                    top: 30.0,
                                  ),
                                  child: Text(
                                    'ISBN',
                                    textAlign: TextAlign.left,
                                    style: TextStyle(fontWeight: FontWeight.bold),
                                  )),
                              Container(
                                  width: 150.0,
                                  margin: EdgeInsets.only(bottom: 10.0, top: 3.0),
                                  child: Text(
                                    'ISBN HERE',
                                    softWrap: true,
                                    overflow: TextOverflow.ellipsis,
                                    maxLines: 3,
                                  )),
                              Container(
                                margin: EdgeInsets.only(bottom: 3.0, top: 10.0),
                                child: Text('Author',
                                    style: TextStyle(fontWeight: FontWeight.bold)),
                              ),
                              Container(
                                margin: EdgeInsets.only(bottom: 10.0, top: 3.0),
                                child: Text(
                                  book.record.coverAuthors,
                                ),
                              ),
                              Container(
                                margin: EdgeInsets.only(bottom: 3.0, top: 10.0),
                                child: Text('Format',
                                    style: TextStyle(fontWeight: FontWeight.bold)),
                              ),
                              Container(
                                margin: EdgeInsets.only(bottom: 10.0, top: 3.0),
                                child: Text(
                                  volumelist.items[index].volumeinfo.printType,
                                ),
                              ),
                              Container(
                                margin: EdgeInsets.all(10.0),
                                child: Column(
                                  children: <Widget>[
                                    FlatButton(
                                      onPressed: () {},
                                      child: Text(
                                        'VIEW MORE DETAILS',
                                        style: TextStyle(color: Colors.deepPurple),
                                      ),
                                    ),
                                  ],
                                ),
                              )
                            ],
                          )),
                    )
    

    and the api call itself:

    Future<VolumeJson> getRelateds() async {
        print('Im Starting');
        final jsonResponse =
            await http.get('https://www.googleapis.com/books/v1/volumes?q=${isbn}');
    
        var jsonBody = json.decode(jsonResponse.body);
        //print(jsonBody);
    
        volumelist = VolumeJson.fromJson(jsonBody);
    
    
      }