2

Here is yet another "Expected a value of type 'Map<String, dynamic>', but got one of type 'List'" questions. I've scoured several Stack Overflow posts on the subject including the following:

I've also tried to follow this Flutter cookbook example.

So, I want to simply call an API that returns a JSON list of lists. Each one of those inner lists of strings corresponds to a class object I've defined below called 'Provider'. I have created class factory methods to map the JSON to my 'Provider' class:

  • factory Provider.fromJsonMap(Map<String, dynamic> json) # The preferred way to call
  • factory Provider.fromJsonListDynamic(List<dynamic> json)

I would prefer to use the first factory method, rather than the second, because I would like to reference each string by it's name, not an array index as you will see in the code.

UPDATE:

As @OmiShah pointed out, the serialized JSON I was passing back from my Python API had no schema, so my deserialized JSON response contains no information about the data. So I couldn't make references to the data like so:

json["name"]

So I changed my Python API to serialize a list of strongly typed class objects and pass that I back to flutter as JSON. Here is a sample of what that data looks like now in Python before it's passed back to flutter:

[
    Provider(name='Google Translate API', id='google.translate_api.v3', img_url='ggl.png'),
    Provider(name='Microsoft Translator', id='microsoft.translator.v3', img_url='mcs.png'),
    Provider(name='Amazon Translate API', id='amazon.translate.api.v2', img_url='aws.png'),
]

And this is what that data looks like after it's deserialized by flutter:

final List<dynamic> listProviders = jsonDecode(response.body);

// contents of listProviders
[
    "Provider(name='Google Translate API', id='google.translate_api.v3', img_url='ggl.png')",
    "Provider(name='Microsoft Translator', id='microsoft.translator.v3', img_url='mcs.png')",
    "Provider(name='Amazon Translate API', id='amazon.translate.api.v2', img_url='aws.png')",
]

I then cast it as list of maps (listMap) and then attempt to map each object to my 'Provider' class object (providerMap) and finally I convert providerMap to a list:

final List<dynamic> listProviders = jsonDecode(response.body);
final List<Map<String, dynamic>> listMap = listProviders.cast<Map<String, dynamic>>();
var providerMap = listMap.map<Provider>((json) => Provider.fromJsonMap(json));
List<Provider> providers = providerMap.toList();

I get the following error when I attempt to convert it to a list:

Error: Expected a value of type 'Map<String, dynamic>', but got one of type 'String'

I am relatively new to Flutter. I would like to pass data around as strongly typed objects and I want to do it in a way that makes sense.

The custom class object I created:

class Provider
{
    final String name;
    final String id;
    final String imageUrl;

    Provider( {required this.name, required this.id, required this.imageUrl });

    // Calling this function fails 
    factory Provider.fromJsonMap(Map<String, dynamic> json)
    {
        Provider provider = Provider
        (           
            name:     json["name"]     as String,
            id:       json["id"]       as String,
            imageUrl: json["imageUrl"] as String,
        );

        return provider;
    }

    // Calling this function works
    factory Provider.fromJsonListDynamic(List<dynamic> json)
    {
        Provider provider = Provider
        (
            name:     json[0] as String,
            id:       json[1] as String,
            imageUrl: json[2] as String,
        );

        return provider;
    }
}

And it's called in this Future async function in a PageState class:

class _DetectorPageState extends State<DetectorPage>
{
    ...

    Future<List<Provider>> getMtProviders() async 
    {
        Uri url = Uri.parse(SOME_API_URL);
        http.Response response = await http.get(url);

        if (response.statusCode == 200) 
        {
            // THIS CODE DOES NOT WORK
            final List<dynamic> listProviders = jsonDecode(response.body);
            final List<Map<String, dynamic>> listMap = listProviders.cast<Map<String, dynamic>>();
            var providerMap = listMap.map<Provider>((json) => Provider.fromJsonMap(json));
            List<Provider> providers = providerMap.toList();
        
            // THIS CODE WORKS
            // List<dynamic> listProviders = jsonDecode(response.body);
            // List<Provider> providers = listProviders.map((provider) => Provider.fromJsonListDynamic(provider as List<dynamic>)).toList();

            return providers;
        } 
        else 
        {
            print('Request failed with status: ${response.statusCode}.');
            return [];
        }
    }
}
4
  • 2
    because json["name"] and so on doesn't exits! There is no value with those keys in your JSON which is why it gets failed ! Commented Jul 8, 2023 at 6:18
  • @OMiShah, thanks for pointing that out! As I inspect the JSON that is returned from the API, that is a GLARING oversight that I missed. Why doesn't flutter/dart catch this? Why can't I step thru the Provider.fromJsonMap factory method to see what's going on? So, the problem is with the API code returning the JSON. I'm not naming objects and properties there. Commented Jul 8, 2023 at 20:31
  • @OMiShah, so in essence what I should be doing is serializing my list of objects in my python API code in such a way that includes the schema. So each object should be a class object. Commented Jul 8, 2023 at 20:45
  • @OMiShah, I made sure to include the schema of the data when I serialize the JSON in my python API, but I still get that "Expected a value of type... " error. I've updated my question to reflect that. Your help is appreciated! Commented Jul 9, 2023 at 2:34

1 Answer 1

1

The problem was with the JSON serialization in my python API. I need to serialize a list of dictionary objects that contain my data and not serialize a list of custom class objects.

providers_dict = \   # Sample Data
[
    {"name": "Google Translate API", "id": "google.translate_api.v3", "img_url": "ggl_translate.png"},
    {"name": "Microsoft Translator", "id": "microsoft.translator.v3", "img_url": "mcs_translate.png"},
    {"name": "Amazon Translate API", "id": "amazon.translate.api.v2", "img_url": "aws_translate.png"},
]

Then you call the json.dumps method to serialize the data into JSON like so:

providers_json = json.dumps(providers_dict)
return providers_json
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.