flutterdarthere-api

Error on getting API response (HERE maps rest API)


I'm new to flutter so bear with me that. I am currently making an application that uses HERE Maps API to get location data, but I'm getting "An error has occurred!", which comes when snapshot has no data.

import 'dart:async';
import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

// To parse this JSON data, do
//
//     final hereRestLocation = hereRestLocationFromJson(jsonString);

HereRestLocation hereRestLocationFromJson(String str) => HereRestLocation.fromJson(json.decode(str));

String hereRestLocationToJson(HereRestLocation data) => json.encode(data.toJson());

class HereRestLocation {
    List<Item> items;

    HereRestLocation({
        required this.items,
    });

    factory HereRestLocation.fromJson(Map<String, dynamic> json) => HereRestLocation(
        items: List<Item>.from(json["items"].map((x) => Item.fromJson(x))),
    );

    Map<String, dynamic> toJson() => {
        "items": List<dynamic>.from(items.map((x) => x.toJson())),
    };
}

//from here
// Future<http.Response> fetchHereRestLocation(http.Client client) async {
//   return client.get(Uri.parse('https://discover.search.hereapi.com/v1/discover?at=40.7307999,-73.9973085&limit=2&q=Liberty&apiKey=**My API key here**'));
// }

List <HereRestLocation> parseHereRestLocation(String responseBody) {
  final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
  return parsed.map<HereRestLocation>((json) => HereRestLocation.fromJson(json)).toList();
}

Future <List<HereRestLocation>> fetchHereRestLocation(http.Client client) async {
  final response = await client.get(Uri.parse('https://discover.search.hereapi.com/v1/discover?at=40.7307999,-73.9973085&limit=2&q=Liberty&apiKey=**My API key here**'));
  // return parseHereRestLocation(response.body);
  // Use the compute function to run parsePhotos in a separate isolate.
  return compute(parseHereRestLocation,response.body);
}

//to here
class Item {
    String title;
    String id;
    String language;
    String resultType;
    String localityType;
    ItemAddress address;
    Highlights highlights;

    Item({
        required this.title,
        required this.id,
        required this.language,
        required this.resultType,
        required this.localityType,
        required this.address,
        required this.highlights,
    });

    factory Item.fromJson(Map<String, dynamic> json) => Item(
        title: json["title"],
        id: json["id"],
        language: json["language"],
        resultType: json["resultType"],
        localityType: json["localityType"],
        address: ItemAddress.fromJson(json["address"]),
        highlights: Highlights.fromJson(json["highlights"]),
    );

    Map<String, dynamic> toJson() => {
        "title": title,
        "id": id,
        "language": language,
        "resultType": resultType,
        "localityType": localityType,
        "address": address.toJson(),
        "highlights": highlights.toJson(),
    };
}

class ItemAddress {
    String label;
    String countryCode;
    String countryName;
    String state;
    String county;
    String city;

    ItemAddress({
        required this.label,
        required this.countryCode,
        required this.countryName,
        required this.state,
        required this.county,
        required this.city,
    });

    factory ItemAddress.fromJson(Map<String, dynamic> json) => ItemAddress(
        label: json["label"],
        countryCode: json["countryCode"],
        countryName: json["countryName"],
        state: json["state"],
        county: json["county"],
        city: json["city"],
    );

    Map<String, dynamic> toJson() => {
        "label": label,
        "countryCode": countryCode,
        "countryName": countryName,
        "state": state,
        "county": county,
        "city": city,
    };
}

class Highlights {
    List<Title> title;
    HighlightsAddress address;

    Highlights({
        required this.title,
        required this.address,
    });

    factory Highlights.fromJson(Map<String, dynamic> json) => Highlights(
        title: List<Title>.from(json["title"].map((x) => Title.fromJson(x))),
        address: HighlightsAddress.fromJson(json["address"]),
    );

    Map<String, dynamic> toJson() => {
        "title": List<dynamic>.from(title.map((x) => x.toJson())),
        "address": address.toJson(),
    };
}

class HighlightsAddress {
    List<Title> label;
    List<Title> city;

    HighlightsAddress({
        required this.label,
        required this.city,
    });

    factory HighlightsAddress.fromJson(Map<String, dynamic> json) => HighlightsAddress(
        label: List<Title>.from(json["label"].map((x) => Title.fromJson(x))),
        city: List<Title>.from(json["city"].map((x) => Title.fromJson(x))),
    );

    Map<String, dynamic> toJson() => {
        "label": List<dynamic>.from(label.map((x) => x.toJson())),
        "city": List<dynamic>.from(city.map((x) => x.toJson())),
    };
}

class Title {
    int start;
    int end;

    Title({
        required this.start,
        required this.end,
    });

    factory Title.fromJson(Map<String, dynamic> json) => Title(
        start: json["start"],
        end: json["end"],
    );

    Map<String, dynamic> toJson() => {
        "start": start,
        "end": end,
    };
}



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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    const appTitle = 'Isolate Demo';

    return const MaterialApp(
      title: appTitle,
      home: MyHomePage(title: appTitle),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: FutureBuilder<List<HereRestLocation>>(
        future: fetchHereRestLocation(http.Client()),
        builder: (context, snapshot) {
          if (snapshot.hasError) {
            return const Center(
              child: Text('An error has occurred!'),
            );
          } else if (snapshot.hasData) {
            return MapList(items: snapshot.data!);
          } else {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }
        },
      ),
    );
  }
}

class MapList extends StatelessWidget {
  const MapList({super.key, required this.items});

  final List<HereRestLocation> items;

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
      ),
      itemCount: items.length,
      itemBuilder: (context, index) {
        return Text(items[index].title);
      },
    );
  }
}

If needed, JSON response for the above API call from browser is like:

{"items":[{"title":"Liberty","id":"here:pds:place:840dr5r0-54fff946ce707baf510ad4123b26813d","language":"en","ontologyId":"here:cm:ontology:liberty","resultType":"place","address":{"label":"Liberty, 2509 Victory Blvd, Staten Island, NY 10314-6634, United States","countryCode":"USA","countryName":"United States","stateCode":"NY","state":"New York","county":"Richmond","city":"Staten Island","district":"Graniteville","street":"Victory Blvd","postalCode":"10314-6634","houseNumber":"2509"},"position":{"lat":40.61038,"lng":-74.14678},"access":[{"lat":40.61022,"lng":-74.14673}],"distance":18390,"categories":[{"id":"700-7600-0116","name":"Gas Station","primary":true}],"chains":[{"id":"4792","name":"Liberty"}],"references":[{"supplier":{"id":"core"},"id":"1130469039"},{"supplier":{"id":"yelp"},"id":"KbW5ssi1UCdbVd_Oodxe7w"}],"contacts":[{"phone":[{"value":"+17189826797"},{"value":"+17189829369"}],"www":[{"value":"http‍://www.liberty.edu"}]}],"openingHours":[{"text":["Mon-Sun: 00:00 - 24:00"],"isOpen":true,"structured":[{"start":"T000000","duration":"PT24H00M","recurrence":"FREQ:DAILY;BYDAY:MO,TU,WE,TH,FR,SA,SU"}]}],"payment":{"methods":[{"id":"mastercard","accepted":true}]}},{"title":"Liberty","id":"here:pds:place:840dr4y0-57e980bf79d04227a9cd14a94e7c9384","language":"en","ontologyId":"here:cm:ontology:liberty","resultType":"place","address":{"label":"Liberty, 118 US Highway 202, Ringoes, NJ 08551-1920, United States","countryCode":"USA","countryName":"United States","stateCode":"NJ","state":"New Jersey","county":"Hunterdon","city":"Ringoes","street":"US Highway 202","postalCode":"08551-1920","houseNumber":"118"},"position":{"lat":40.46667,"lng":-74.8599},"access":[{"lat":40.46666,"lng":-74.85998}],"distance":78526,"categories":[{"id":"700-7600-0116","name":"Gas Station","primary":true},{"id":"600-6000-0061","name":"Convenience Store"}],"chains":[{"id":"4792","name":"Liberty"}],"contacts":[{"phone":[{"value":"+19088066633"}],"www":[{"value":"http‍://www.liberty.edu","categories":[{"id":"700-7600-0116"}]}]}],"payment":{"methods":[{"id":"mastercard","accepted":true}]}}]}

I tried using https://app.quicktype.io/ to get classes as well, but here I am.


Solution

  • Future<HereRestLocation> fetch() async {
        final response = await http.get(Uri.parse(URL));
    
        final jsonResponse = jsonDecode(response.body);
    
        if (response.statusCode == 200) {
          HereRestLocation hereRestLocation = HereRestLocation.fromJson(jsonResponse);
    
          for (Item item in hereRestLocation.items) {
            debugPrint(item.id.toString());
          }
    
          return hereRestLocation;
        } else {
          throw Exception("Something Went Wrong");
        }
      }