skip to Main Content

Using Flutter, I would like to read a nested rest api.

I found this free rest api here: https://dictionaryapi.dev/

But I don’t understand how to create a class for a nested json response. I’ve read that I don’t actually need to create a class, but rather use a package to process the json response. T/F?

Could you please outline how to construct a class for the above example.

2

Answers


  1. The json.decode method mentioned will convert a JSON string to Map<String, dynamic> (or a list depending on data shape). However if the data is deeply nested it will probably be preferable to create a class and either manually unpack the data in a fromJson constructor or use the JsonSerializable package to generate that method for you.

    Manual approach: https://medium.com/@raphaelrat_62823/consuming-rest-api-in-flutter-a-guide-for-developers-2460d90320aa

    Generated approach: https://pub.dev/packages/json_serializable

    Login or Signup to reply.
  2. You are right, there are packages like json_serializable or dart:convert that help parse JSON, but to maintain good maintainability and type safety, it is a good practice to make model classes for nested JSON responses at least in complex apps.

    Checkout below API response.

    [
      {
        "word": "example",
        "phonetics": [
          {
            "text": "/ɪɡˈzɑːmp(ə)l/",
            "audio": "https://lex-audio.useremarkable.com/mp3/example_us.mp3"
          }
        ],
        "meanings": [
          {
            "partOfSpeech": "noun",
            "definitions": [
              {
                "definition": "A thing characteristic of its kind or illustrating a general rule.",
                "example": "this is a good example of bad behavior"
              }
            ]
          }
        ]
      }
    ]
    

    It has a nested structure containing lists of objects (like phonetics and meanings). Lets try out the manual approach(if you need generated approach learn freezed package) to explain your scope.

    As the first step You need to create classes to represent this structure. Checkout the below example.

    class DictionaryEntry {
      final String word;
      final List<Phonetic> phonetics;
      final List<Meaning> meanings;
    
      DictionaryEntry({required this.word, required this.phonetics, required this.meanings});
    
      factory DictionaryEntry.fromJson(Map<String, dynamic> json) {
        return DictionaryEntry(
          word: json['word'],
          phonetics: (json['phonetics'] as List).map((e) => Phonetic.fromJson(e)).toList(),
          meanings: (json['meanings'] as List).map((e) => Meaning.fromJson(e)).toList(),
        );
      }
    }
    
    class Phonetic {
      final String text;
      final String audio;
    
      Phonetic({required this.text, required this.audio});
    
      factory Phonetic.fromJson(Map<String, dynamic> json) {
        return Phonetic(
          text: json['text'],
          audio: json['audio'],
        );
      }
    }
    
    class Meaning {
      final String partOfSpeech;
      final List<Definition> definitions;
    
      Meaning({required this.partOfSpeech, required this.definitions});
    
      factory Meaning.fromJson(Map<String, dynamic> json) {
        return Meaning(
          partOfSpeech: json['partOfSpeech'],
          definitions: (json['definitions'] as List).map((e) => Definition.fromJson(e)).toList(),
        );
      }
    }
    
    class Definition {
      final String definition;
      final String example;
    
      Definition({required this.definition, required this.example});
    
      factory Definition.fromJson(Map<String, dynamic> json) {
        return Definition(
          definition: json['definition'],
          example: json['example'] ?? '', // In case there is no example
        );
      }
    }
    

    After you create above model classes, you can fetch and parse the API response like below.

    import 'dart:convert';
    import 'package:http/http.dart' as http;
    
    Future<List<DictionaryEntry>> fetchWordData(String word) async {
      final response = await http.get(Uri.parse('https://api.dictionaryapi.dev/api/v2/entries/en/$word'));
    
      if (response.statusCode == 200) {
        List<dynamic> jsonResponse = json.decode(response.body);
        return jsonResponse.map((entry) => DictionaryEntry.fromJson(entry)).toList();
      } else {
        throw Exception('Failed to load word data');
      }
    }
    

    Also If you dont care about creating models(not recommended) you can directly access the nested data using simple indexing with json['key'].

    Future<void> fetchData() async {
      final response = await http.get(Uri.parse('https://api.example.com/data'));
    
      if (response.statusCode == 200) {
        Map<String, dynamic> jsonData = json.decode(response.body);
    
        // Accessing data directly from the JSON response
        String name = jsonData['data1']['data2']['name'];
        int age = jsonData['data1']['data2']['age'];
        String city = jsonData['data1']['data2']['address']['city'];
        String zipcode = jsonData['data1']['data2']['address']['zipcode'];
    
        print('Name: $name');
        print('Age: $age');
        print('City: $city');
        print('Zipcode: $zipcode');
      } else {
        throw Exception('Failed to load data');
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search