Unexpected null value – API Flutter

Issue

When I start the project I got an unexpected null value.
I keep getting this error with this API, I don’t have certain of what can be.
you can check here

api link: https://ffxivcollect.com/api/mounts/257

response

{
  "id": 257,
  "name": "Island Eggplant Knight",
  "description": "Summon forth your island Eggplant Knight, an oversized vegetable embodiment of chivalry.",
  "enhanced_description": "Hailing from the selfsame land as the Tomato King, the Eggplant Knight shared a crate with the sovereign when they were shipped out. However, he fell overboard when the vessel encountered rough seas, and drifted for days before being deposited on a desert island. Among other feats, he prides himself on having played a key role in the founding of the West Mandra Empire.",
  "tooltip": "I thought ye were a feral turnip, a murderous eggplant, or summat like that!    - Tiny Trader",
  "movement": "Terrestrial",
  "seats": 1,
  "order": 240,
  "order_group": 99,
  "patch": "6.2",
  "item_id": null,
  "tradeable": false,
  "owned": "3.9%",
  "image": "https://ffxivcollect.com/images/mounts/large/257.png",
  "icon": "https://ffxivcollect.com/images/mounts/small/257.png",
  "bgm": "https://ffxivcollect.com/music/BGM_Ride_MJI.ogg",
  "sources": [
    {
      "type": "Purchase",
      "text": "12,000 Seafarer's Cowries",
      "related_type": null,
      "related_id": null
    }
  ]
}

I’m using quick type to convert the JSON to dart and paste in the model only adding Required.

my home page:

Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(''),
      ),
      body: ListView.builder(
        itemCount: finalApi!.length,
        itemBuilder: (context, index) {
          return Container(
            child: Text(finalApi![index].description),
          );
        },
      ),
    );
  }
}

url:

class RemoteService {
  Future<List<FinalApi>> getPosts() async {
    var client = http.Client();
    var uri = Uri.parse('https://ffxivcollect.com/api/mounts/257');
    var response = await client.get(uri);
    if (response.statusCode == 200) {
      var json = response.body;
      return finalApiFromJson(json);
    }
    throw Text('aa');
  }
}

my model:

List<FinalApi> finalApiFromJson(String str) =>
    List<FinalApi>.from(json.decode(str).map((x) => FinalApi.fromJson(x)));

String finalApiToJson(List<FinalApi> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class FinalApi {
  FinalApi({
    required this.id,
    required this.name,
    required this.description,
    required this.enhancedDescription,
    required this.tooltip,
    required this.movement,
    required this.seats,
    required this.order,
    required this.orderGroup,
    required this.patch,
    required this.itemId,
    required this.tradeable,
    required this.owned,
    required this.image,
    required this.icon,
    required this.bgm,
    required this.sources,
  });

  int id;
  String name;
  String description;
  String enhancedDescription;
  String tooltip;
  String movement;
  int seats;
  int order;
  int orderGroup;
  String patch;
  dynamic itemId;
  bool tradeable;
  String owned;
  String image;
  String icon;
  String bgm;
  List<Source> sources;

  factory FinalApi.fromJson(Map<String, dynamic> json) => FinalApi(
        id: json["id"],
        name: json["name"],
        description: json["description"],
        enhancedDescription: json["enhanced_description"],
        tooltip: json["tooltip"],
        movement: json["movement"],
        seats: json["seats"],
        order: json["order"],
        orderGroup: json["order_group"],
        patch: json["patch"],
        itemId: json["item_id"],
        tradeable: json["tradeable"],
        owned: json["owned"],
        image: json["image"],
        icon: json["icon"],
        bgm: json["bgm"],
        sources:
            List<Source>.from(json["sources"].map((x) => Source.fromJson(x))),
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "name": name,
        "description": description,
        "enhanced_description": enhancedDescription,
        "tooltip": tooltip,
        "movement": movement,
        "seats": seats,
        "order": order,
        "order_group": orderGroup,
        "patch": patch,
        "item_id": itemId,
        "tradeable": tradeable,
        "owned": owned,
        "image": image,
        "icon": icon,
        "bgm": bgm,
        "sources": List<dynamic>.from(sources.map((x) => x.toJson())),
      };
}

class Source {
  Source({
    required this.type,
    required this.text,
    required this.relatedType,
    required this.relatedId,
  });

  String type;
  String text;
  dynamic relatedType;
  dynamic relatedId;

  factory Source.fromJson(Map<String, dynamic> json) => Source(
        type: json["type"],
        text: json["text"],
        relatedType: json["related_type"],
        relatedId: json["related_id"],
      );

  Map<String, dynamic> toJson() => {
        "type": type,
        "text": text,
        "related_type": relatedType,
        "related_id": relatedId,
      };
}

Solution

Based on your response, It is returning a single item on map. Therefor the parser will be like

  final data = FinalApi.fromJson(jsonDecode(json));
class RemoteService {
  Future<List<FinalApi>> getPosts() async {
    var client = http.Client();
    var uri = Uri.parse('https://ffxivcollect.com/api/mounts/257');
    var response = await client.get(uri);
    try {
      if (response.statusCode == 200) {
        var json = response.body;
        // finalApiFromJson(json);
        final data = FinalApi.fromJson(jsonDecode(json));
        return [data];
      }
    } catch (e) {
      log(e.toString());
    }

    return [];
  }
}

Answered By – Yeasin Sheikh

Answer Checked By – Timothy Miller (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *