Parsing JSON response to an object or a Map

apexjson

I am completing a challenge for Apex on trailhead. My code is making a callout and receiving certain records in JSON format. I am not able to covert the response into a MAP to process it easily. The response can only be received into a List and further that List cannot be converted to a Map<String, Object>. Please can you see below code and advise what options do I have to traversing the JSON response?

String endpointURL = 'https://th-superbadge-apex.herokuapp.com/equipment?_ga=2.101942977.1923619249.1654550632-503779371.1642224353';

HttpRequest request = new HttpRequest();
Http callOut = new Http();

request.setEndpoint(endpointURL);
request.setMethod('GET');

HttpResponse response = callOut.send(request);

List<Object> listRecords =  (List<Object>) JSON.deserializeUntyped(response.getBody());

//Map<String, Object> m = (Map<String, Object>) listRecords;

if (response.getStatusCode() == 200)
{
    
}

If I uncomment line:

//Map<String, Object> m = (Map<String, Object>) listRecords;

I got following error:

10:02:51.727 Starting Execute Anonymous Apex

Error: Line: 13, Column: 25
Error: Incompatible types since an instance of List<Object> is never an instance of Map<String,Object>

10:02:52.58 ended Execute Anonymous Apex

Best Answer

Despite this appearing as if it's for a superbadge, I think there's enough of a question here to answer that won't defeat the purpose (of the superbadge) here.

Like your error is telling you, you can't cast a List to be a Map. There's no way for Salesforce to know what should be used as the key of the map. The only time that we're really able to turn a List into a Map is when it's a List<SObject> and the Map is a Map<Id, SObject> (Salesforce knows to use the Id field, which every SObject must have, for the key of the map).

The JSON you're getting does appear to be a List, so deserializing it as a List is the right thing to do.

To further dig into your JSON, you will need to iterate over the List<Object> that you have. That'll give you individual instances of Object inside the loop, and those are able to be typecast further. In your case, since the JSON is a List of JSON objects, you'll be able to cast them to a Map<String, Object>

example

String myJson ='[{"color":"red"}, {"color":"green"}, {"color":"blue"}]';

List<Object> jsonList = (List<Object>) JSON.deserializeUntyped(myJson);

for(Object jsonObj :jsonList){
    // Working with untyped deserialization means you're in for a lot of type-casting
    Map<String, Object> internalObj = (Map<String, SObject>)jsonObj;
    String extractedColor = (String)internalObj.get('color');
    system.debug('color = ' + extractedColor);
}