How to parse Nested JSON in flutter?

Viewed 1513

Can anyone tell me how to parse this JSON in flutter.I'M stucked i created classes successfully but getting errors from parse method Here is The JSON

{
    "btcinr": {
        "base_unit": "btc",
        "quote_unit": "inr",
        "low": "3001337.0",
        "high": "3145000.0",
        "last": "3107312.0",
        "type": "SPOT",
        "open": "3085453",
        "volume": "243.1121",
        "sell": "3114335.0",
        "buy": "3106628.0",
        "at": 1646663606,
        "name": "BTC/INR"
    }
}

The method where i'm stuked and getting errors is

Future<List<Map<String, dynamic>>> fetchData() async {
    final response =
        await http.get(Uri.parse("https://api.wazirx.com/api/v2/tickers"));
    if (response.statusCode == 200) {
      final responseJson = json.decode(response.body);
      
    } else {
      throw Exception('Unexpected Error Occured!');
    }
  }

This method is incomplete ,any help will be appreciated Thank You!

4 Answers

Posting this example of a nested JSON request for better understanding. This example has a list of RejectedModel and this model has one nested model Reject in it and the code below is handling it.

Got this format of JSON Response.


[
    {
        "id": 2,
        "service": 200,
        "reject": {
            "id": 8,
            "reason": "sample",
            "order_id": 2,
        }
    },
    {
        "id": 3,
        "service": 600,
        "reject": {
            "id": 12,
            "reason": "sample",
            "order_id": 2,
        }
    }
]

The controller class looks like this

class RejectedModel{
  int id;
  int service;
  Reject reject;
  RejectedModel({required this.id, required this.service, required this.reject});

  factory RejectedModel.fromJson (Map<String,dynamic>json){
    return RejectedModel(id: json['id'],
        service: json['service'],
        reject: Reject.fromJson(json['reject'])  );
  }
}
class Reject{
//this will handel nested object
    int id;
    String reason;
    int order_id;

    Reject({required this.id, required this.reason, required this.order_id,});

    factory Reject.fromJson (Map<String,dynamic>json){
      return Reject(id: json['id'],
          reason: json['reason'],
          order_id: json['order_id']);
    }
}

making the API call in this method. Future<List<RejectedModel>> is the return type of the below method

Future getRejctedOrders() async {
    final response = await http.get(Uri.parse('your url'));

    if(response.statusCode == 200){
      List rejected = json.decode(response.body);
      return rejected.map((e) => RejectedModel.fromJson(e)).toList();
    }
    else{
      throw Exception('something wrong');
    }
}

using this API call in the widget to display the data. Write this <List<RejectedModel>> before ( and after FutureBuilder

FutureBuilder <List<RejectedModel>> (
    future: getRejctedOrders,
    builder: (context,snapshot){
      if(snapshot.hasData){
        final List<RejectedModel>? data = snapshot.data;
        return ListView.builder(
          itemCount: data?.length,
          shrinkWrap: true,
          itemBuilder: (BuildContext context, int index){
            if(index.isNaN){
              return CircularProgressIndicator(color: Colors.grey,);
            }

            Reject rej = data![index].reject;
            //you can make the required widget
            return Text('data ${rej.reason}');

          },
        );
      }
      else{
        return CircularProgressIndicator(color: Colors.grey,);
      }
    },
  )

Following your json object structure, your fetchData method should have the return type of Map<String, Map<String, dynamic>> since it is a Map of a Map.

After updating the return type, the missing part of your code is the casting of your decoded response.body to Map<String, Map<String, dynamic>>.

See the solution below.

Solution:

Future<Map<String, Map<String, dynamic>>> fetchData() async {
    final response =
        await http.get(Uri.parse("https://api.wazirx.com/api/v2/tickers"));
    if (response.statusCode == 200) {
      final responseJson = (json.decode(response.body) as Map).map(
        (key, value) => MapEntry(key as String, value as Map<String, dynamic>));
      return responseJson;
    } else {
      throw Exception('Unexpected Error Occured!');
    }
  }

In a ListView Builder

You can use the method above to display the data in a ListView builder by using it in a FutureBuilder like below:

FutureBuilder<Map<String, Map<String, dynamic>>>(
        future: fetchData(),
        builder: (BuildContext context,
            AsyncSnapshot<Map<String, Map<String, dynamic>>> snapshot) {
          if (snapshot.data == null) {
            return const Center(child: CircularProgressIndicator());
          }

          final data = snapshot.data;

          return ListView.builder(
            itemBuilder: ((context, index) {
              final item = data!.entries.elementAt(index);
              final map = item.value;
              final String baseUnit = map['base_unit'];
              final String quoteUnit = map['quote_unit'];

              final String high = map['high'];
              final String low = map['low'];

              return ListTile(
                title: Text(baseUnit),
                subtitle: Text('High-$high$quoteUnit Low - $low$quoteUnit'),
              );
            }),
            itemCount: data!.entries.length,
          );
        },
      ),

Below is a screenshot of the UI generated from the above code:

enter image description here

I need to be honest, this is a bit of a generic question. But I will try to answer as I understand it. If you want to create a json parsing mechanism. You can use code generation approaches like this website. This generates a huge object for you but at least after you parse the information you can get an object to reference whatever you need.


I got the result from https://api.wazirx.com/api/v2/tickers. Put it to the website above. It generated the code here. I could not share it here because it is too big :)

What you need to do next is:

Future<Autogenerated> fetchData() async {
    final response =
        await http.get(Uri.parse("https://api.wazirx.com/api/v2/tickers"));
    if (response.statusCode == 200) {
      final responseJson = json.decode(response.body);
      final autogenerated = Autogenerated.fromJson(responseJson);
      return autogenerated;
    } else {
      throw Exception('Unexpected Error Occured!');
    }
  }

Future<void> main() async {
  List<Map<String, dynamic>> fetchData2 = await fetchData();

  fetchData2.forEach((element) {
    print(element.runtimeType);
    print(element.keys);
    print(element.values);
  });
  print(fetchData2);
}

Future<List<Map<String, dynamic>>> fetchData() async {
  final response =
      await get(Uri.parse("https://api.wazirx.com/api/v2/tickers"));

  if (response.statusCode == 200) {
    Map<String, dynamic> responseJson = json.decode(response.body);
    // print(responseJson.runtimeType);
    List<Map<String, dynamic>> list = [];
    var cd = responseJson.forEach((key, value) {
      Map<String, dynamic> value2 = Map.of({key: value});
      list.add(value2);
    });

    return list;
  } else {
    throw Exception('Unexpected Error Occured!');
  }
}

Output

_InternalLinkedHashMap<String, dynamic>
1+===========>(btcinr)
({base_unit: btc, quote_unit: inr, low: 3001337.0, high: 3145000.0, last: 3102692.0, type: SPOT, open: 3090720, volume: 256.70627, sell: 3108375.0, buy: 3102776.0, at: 1646668281, name: BTC/INR})
_InternalLinkedHashMap<String, dynamic>
2+===========>(xrpinr)
({base_unit: xrp, quote_unit: inr, low: 56.4, high: 59.7997, last: 59.1699, type: SPOT, open: 58.333, volume: 688814.2, sell: 59.1663, buy: 59.0, at: 1646668281, name: XRP/INR})
_InternalLinkedHashMap<String, dynamic>
3+===========>(ethinr)
({base_unit: eth, quote_unit: inr, low: 200000.0, high: 210582.8, last: 207599.7, type: SPOT, open: 208225, volume: 528.2563, sell: 207672.0, buy: 207506.5, at: 1646668281, name: ETH/INR})
_InternalLinkedHashMap<String, dynamic>
4+===========>(trxinr)
({base_unit: trx, quote_unit: inr, low: 4.6206, high: 4.8, last: 4.782, type: SPOT, open: 4.721, volume: 12397343.0, sell: 4.782, buy: 4.7788, at: 1646668281, name: TRX/INR})
_InternalLinkedHashMap<String, dynamic>
5+===========>(eosinr)
({base_unit: eos, quote_unit: inr, low: 153.49, high: 161.97, last: 159.12, type: SPOT, open: 159, volume: 8064.39, sell: 159.86, buy: 159.02, at: 1646668281, name: EOS/INR})
_InternalLinkedHashMap<String, dynamic>
6+===========>(zilinr)
({base_unit: zil, quote_unit: inr, low: 2.95, high: 3.18, last: 3.14, type: SPOT, open: 3.04, volume: 1926347.0, sell: 3.13, buy: 3.12, at: 1646668281, name: ZIL/INR})
_InternalLinkedHashMap<String, dynamic>
7+===========>(batinr)
({base_unit: bat, quote_unit: inr, low: 49.511, high: 53.0, last: 51.782, type: SPOT, open: 51.799, volume: 42537.25, sell: 52.812, buy: 51.809, at: 1646668281, name: BAT/INR})
_InternalLinkedHashMap<String, dynamic>
8+===========>(zrxinr)
({base_unit: zrx, quote_unit: inr, low: 37.0, high: 39.43, last: 38.59, type: SPOT, open: 38.34, volume: 27340.61, sell: 39.34, buy: 38.48, at: 1646668281, name: ZRX/INR})
_InternalLinkedHashMap<String, dynamic>
9+===========>(reqinr)

enter image description here

SAmple Code

// To parse this JSON data, do
//
//     final bricklink = bricklinkFromJson(jsonString);

import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MyHomePage(title: 'Scanner'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

int myvalue = 0;

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  @override
  void initState() {}

  Future<int> functions() async {
    // do something here
    return Future.value();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Scanner"),
        backgroundColor: Colors.green,
      ),
      body: FutureBuilder(
          future: fetchData(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.done) {
              List<Map<String, dynamic>> data =
                  snapshot.data as List<Map<String, dynamic>>;
              return Container(
                color: Colors.white,
                child: ListView.builder(
                  itemCount: data.length,
                  itemBuilder: (context, index) {
                    return ListTile(
                      title: Text((data[index] as Map<String, dynamic>)
                          .keys
                          .single
                          .toString()),
                      subtitle: Text((data[index] as Map<String, dynamic>)
                          .values
                          .single
                          .toString()),
                      leading: CircleAvatar(
                          child: Text((data[index] as Map<String, dynamic>)
                              .keys
                              .single[0]
                              .toString())),
                    );
                  },
                ),
              );
            } else {
              return Center(
                child: Container(
                  height: 50,
                  width: 50,
                  child: CircularProgressIndicator(),
                ),
              );
            }
          }),
    );
  }
}

class Page1 extends StatelessWidget {
  var _controller = TextEditingController();

  Page1({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.max,
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Center(
          child: Container(
            height: 55,
            child: ElevatedButton(
                style: ButtonStyle(
                    backgroundColor: MaterialStateProperty.all(Colors.green)),
                onPressed: () {},
                child: Text(
                  "Choose the Date",
                  style: TextStyle(fontSize: 25),
                )),
          ),
        ),
        Center(
          child: Text(
            "No date Choosen",
            style: TextStyle(fontSize: 16),
          ),
        ),
        Center(
          child: Wrap(
            // direction: Axis.vertical,
            children: [
              RadioListTile(
                  title: Text("home"),
                  value: "Home",
                  groupValue: "Home",
                  onChanged: (v) {}),
              RadioListTile(
                  title: Text("Company"),
                  value: "Company",
                  groupValue: "Home",
                  onChanged: (v) {}),
              RadioListTile(
                  title: Text("Other"),
                  value: "Other",
                  groupValue: "Home",
                  onChanged: (v) {}),
            ],
          ),
        ),
        Center(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextFormField(
              controller: _controller,
              decoration: InputDecoration(
                hintText: "Enter the number of bottels",
                border: OutlineInputBorder(),
              ),
            ),
          ),
        ),
        Container(
          // height: 75,
          padding: EdgeInsets.symmetric(horizontal: 50),
          child: Row(
            children: [
              Expanded(
                child: Container(
                  height: 55,
                  child: ElevatedButton(
                      style: ButtonStyle(
                          backgroundColor:
                              MaterialStateProperty.all(Colors.green)),
                      onPressed: () {},
                      child: Text(
                        "Start",
                        style: TextStyle(fontSize: 25),
                      )),
                ),
              ),
            ],
          ),
        )
      ],
    );
  }
}

Future<List<Map<String, dynamic>>> fetchData() async {
  final response =
      await get(Uri.parse("https://api.wazirx.com/api/v2/tickers"));

  if (response.statusCode == 200) {
    Map<String, dynamic> responseJson = json.decode(response.body);
    // print(responseJson.runtimeType);
    List<Map<String, dynamic>> list = [];
    var cd = responseJson.forEach((key, value) {
      Map<String, dynamic> value2 = Map.of({key: value});
      list.add(value2);
    });

    return list;
  } else {
    throw Exception('Unexpected Error Occured!');
  }
}
Related