+ Start a Discussion
SinanBunniSinanBunni 

HTTP and Basic Callout Trailhead Challange

Hello,

I am trying to solve the challange of the HTTP and Basic Callout module of Salesforce trailhead and I am having some queries in which you could point to the right direction:

1- The challange asked us to call this URL https://th-apex-http-callout.herokuapp.com/animals/:id in method getAnimalNameById... should that URL be in this form instead of the above https://th-apex-http-callout.herokuapp.com/animals?id ? Where id is a parameter in the URL.

2- When I tried to check the solution of the challange, Salesforce generated that error for me
"Challenge Not yet complete... here's what's wrong: 
Executing the 'getAnimalNameById' method on 'AnimalLocator' failed. Make sure the method exists with the name 'getAnimalNameById', is public and static, accepts an Integer and returns a String."
despite that my class implementation has this method declared as public static String as below in the code snippet:
 
public class AnimalLocator {
	
	public static String getAnimalNameById(Integer id) {
		
		Http http = new Http();
		HttpRequest request = new HttpRequest();
		request.setEndpoint('https://th-apex-http-callout.herokuapp.com/animals?id');
		request.setMethod('GET');
		
		HttpResponse response = http.send(request);
		List<Object> animals = NULL;
		String returnValue = NULL;
		
		// if the request was successful, then parse the JSON response
		if (response.getStatusCode() == 200) {
			Map<String, Object> result = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
			animals = (List<Object>) result.get('animals');
			System.debug(animals);
		}
		
		if (animals.size() > 0 && animals != NULL && id < animals.size()) {
			returnValue = (String) animals.get(id);
		}
		
		return returnValue;
	} // end getAnimalNameById method
    
} // end AnimalLocator class

I would appreciate your help in this post.

Thank you,

Sinan
Best Answer chosen by SinanBunni
pconpcon
No, you should be replacing the Id at the end of the url with the id passed into the method

Try
 
request.setEndpoint('https://th-apex-http-callout.herokuapp.com/animals/' + id);

instead

All Answers

pconpcon
No, you should be replacing the Id at the end of the url with the id passed into the method

Try
 
request.setEndpoint('https://th-apex-http-callout.herokuapp.com/animals/' + id);

instead
This was selected as the best answer
SinanBunniSinanBunni
Hello pcon,

Thank you for your prompt reply. That tip helped me to solve the problem I am facing and getting the 500 points of the challange. Thanks. Sinan
Ajay Ghuge 6Ajay Ghuge 6
Hi There ,

I wrote the class in the following manner : 
 
public class AnimalLocator
{

  public static String getAnimalNameById(Integer id)
   {
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint('https://th-apex-http-callout.herokuapp.com/animals/'+id);
        request.setMethod('GET');
        HttpResponse response = http.send(request);
        String strResp = '';
         
        if (response.getStatusCode() == 200) {
            // Deserializes the JSON string into collections of primitive data types.
       Map<String, Object> results = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
           Object animals = (Object) results.get('name');
          strResp +=string.valueof(animals ) ;
        }
        return strResp ;
   }
  
}

But facing 

Challenge Not yet complete... here's what's wrong: 
Executing the 'getAnimalNameById' method on 'AnimalLocator' failed. Make sure the method exists with the name 'getAnimalNameById', is public and static, accepts an Integer and returns a String.

Can anyone explain what is wrong in this ?

Regards,
Ajay 
pconpcon
Ajay: Not sure why your are getting this.  Having the following works for me
 
public class AnimalLocator {
    public class Animal {
        public Integer id;
        public String name;
        public String eats;
        public String says;
    }
    
    public class AnimalResult {
        public Animal animal;
    }

	public static String getAnimalNameById(Integer id) {
        Http http = new Http();
        
        HttpRequest request = new HttpRequest();
        request.setEndpoint('https://th-apex-http-callout.herokuapp.com/animals/' + id);
        request.setMethod('GET');
        
        HttpResponse response = http.send(request);
        AnimalResult result = (AnimalResult) JSON.deserialize(response.getBody(), AnimalResult.class);
        return result.animal.name;
   }
}

If you open the developer console and run the following what do you get back?
 
System.debug(AnimalLocator.getAnimalNameById(1));
Ajay Ghuge 6Ajay Ghuge 6
Hi Pcon ,

Following code works for me after checking the response.
 
public class AnimalLocator
{

  public static String getAnimalNameById(Integer id)
   {
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint('https://th-apex-http-callout.herokuapp.com/animals/'+id);
        request.setMethod('GET');
        HttpResponse response = http.send(request);
          String strResp = '';
           system.debug('******response '+response.getStatusCode());
           system.debug('******response '+response.getBody());
        // If the request is successful, parse the JSON response.
        if (response.getStatusCode() == 200) 
        {
            // Deserializes the JSON string into collections of primitive data types.
           Map<String, Object> results = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
            // Cast the values in the 'animals' key as a list
           Map<string,object> animals = (map<string,object>) results.get('animal');
            System.debug('Received the following animals:' + animals );
            strResp = string.valueof(animals.get('name'));
            System.debug('strResp >>>>>>' + strResp );
        }
        return strResp ;
   }
  
}

Thanks for your help !!! 

Regards,
Ajay 
Sai Sasidhar BhagavathulaSai Sasidhar Bhagavathula
Hi,

I've written the code in the below format.


public class AnimalLocator {    
    public class Animal{
        public Animal Animal1;
    }
    public class Animal1 {
        public Integer id;
        public String name;
        public String eats;
        public String says;
    }        
    public static String getAnimalNameById(Integer id) {
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint('https://th-apex-http-callout.herokuapp.com/animals/' + id);
        request.setMethod('GET');
        HttpResponse response = http.send(request);
        Animal anm = (Animal) JSON.deserialize(response.getBody(), Animal.class);
        return anm.Animal1.name;
 }
}

But I'm getting error as "Variable does not exist: name"

Can you guys plz help me out on this.....

Thanks in Advance !!!
pconpcon
Your problem is the declaration of your class. Right now your Animal class had a circular declaration since animal1 is of type Animal. See my reply above for the class declaration and deserialization
Sai Sasidhar BhagavathulaSai Sasidhar Bhagavathula
Sorry...Can you please elaborate what do you mean by circular declaration please.

Thanks in Advance !!!
pconpcon
What you are trying to do is have a variable named animal that is a reference to your Animal1 class. It needs to be named animal so that it can be deserialized into the object. Right now you have a variable named Animal1 that points to your Animal class that has a variable named Animal1 that points up your Animal class that has a variable... In a circle. What you want to do is say
 
public Animal1 animal;

This will define a variable named animal that points up your Animal1 class that has all of your expected fields.  Then you would reference name by saying
 
an.animal.name

 
Sai Sasidhar BhagavathulaSai Sasidhar Bhagavathula
Thanks for detailed explanation :)

Got it and it resolved my issue... 
Sai Sasidhar BhagavathulaSai Sasidhar Bhagavathula
Hi,

I've written test class after checking challenge facing the issue as per below.
Could you please check

Code :

public class AnimalLocator {    

    public class Animal {
        public Integer id;
        public String name;
        public String eats;
        public String says;
    }        
    public static String getAnimalNameById(Integer id) {
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint('https://th-apex-http-callout.herokuapp.com/animals/' + id);
        request.setMethod('GET');
        HttpResponse response = http.send(request);
        Animal anm = (Animal) JSON.deserialize(response.getBody(),Animal.class);
        string st = anm.name;
        return st;
 }
}

Error :

Challenge not yet complete
Executing the 'getAnimalNameById' method on 'AnimalLocator' failed. Make sure the method exists with the name 'getAnimalNameById', is public and static, accepts an Integer and returns a String.

Thanks in Advance !!

 
pconpcon
If you run it in the developer console, does the method work as expected?  My guess is no.  Because your deserialization is wrong.  As stated before, you need the wrapper to match the object structure coming back from the JSON data.  I would recommend reading over this article [1] about JSON deserialization in Apex to understand a little bit clearer.  However, if you visit one of the animal records, you will see this data returned
 
{
    "animal": {
        "id": 1,
        "name": "chicken",
        "eats": "chicken food",
        "says": "cluck cluck"
     }
}

This has a variable named "animal" that you have to have in your main class.  Then that variable contains data about the animal.
 
public class Animal {
    public Integer Id
    public String name;
    public String eats;
    public String says;
}

public class AnimalWrapper {
    public Animal animal;
}

This allows you deserialize the data returned from the result as expected.  By using
 
AnimalWrapper wrapper = (AnimalWrapper) JSON.deserialize(response.getBody(), AnimalWrapper.class);
return wrapper.animal.name;

​​​​​​​NOTE: When adding code please use the "Add a code sample" button (icon <>) to increase readability and make it easier to reference.
vikas gupta 93vikas gupta 93
Try this by using JSONParser, this works perfect!!!
Animal Locator:
public class AnimalLocator {
    public static String getAnimalNameById(Integer id) {
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint('https://th-apex-http-callout.herokuapp.com/animals/'+id);
        request.setMethod('GET');
        HttpResponse response = http.send(request);
       	/*Map<String,Object> results = (Map<String,Object>)JSON.deserializeUntyped(response.getBody());
        system.debug('---->results'+results);
        List<Object> animals = (List<Object>) results.get('animal');
        system.debug('---->animal'+animals);*/
        Map<Integer,String> mapAnimal = new Map<Integer,String>();
        Integer varId;
        String varName;
        JSONParser parser1= JSON.createParser(response.getBody());
        while (parser1.nextToken() != null) {
            if ((parser1.getCurrentToken() == JSONToken.FIELD_NAME) && (parser1.getText() == 'id')) {
                // Get the value.
                parser1.nextToken();
                // Fetch the ids for all animals in JSON Response.
                varId=parser1.getIntegerValue();
                System.debug('---->varId-->'+varID);
                parser1.nextToken();
            }
            if ((parser1.getCurrentToken() == JSONToken.FIELD_NAME) && (parser1.getText() == 'name')) {
                parser1.nextToken();
                // Fetch the names for all animals in JSON Response.
                varName=parser1.getText();
                System.debug('---->varName-->'+varName);
            }
            mapAnimal.put(varId,varName);
        }
        system.debug('---->mapAnimal-->'+mapAnimal);
        return mapAnimal.get(id); 
        
    }
}

Mock Test Class:
@isTest
global class AnimalLocatorMock implements HttpCalloutMock {
    // Implement this interface method
    global HTTPResponse respond(HTTPRequest request) {
        // Create a fake response
        HttpResponse response = new HttpResponse();
        response.setHeader('Content-Type', 'application/json');
        response.setBody('{"animal":[{"id":1,"name":"chicken","eats":"chicken food","says":"cluck cluck"},{"id":2,"name":"duck","eats":"worms","says":"pek pek"}]}');
        response.setStatusCode(200);
        return response; 
    }
}
Test Class:
@isTest
private class AnimalLocatorTest {
@isTest static void testGetCallout() {
    // Set mock callout class 
    Test.setMock(HttpCalloutMock.class, new AnimalLocatorMock()); 
    // This causes a fake response to be sent
    // from the class that implements HttpCalloutMock. 
    String response = AnimalLocator.getAnimalNameById(1);
    system.debug('Test Response1--->'+response);
    String expectedValue = 'chicken';
    System.assertEquals(expectedValue,response);
    String response2 = AnimalLocator.getAnimalNameById(2);
    system.debug('Test Response2--->'+response2);
    String expectedValue2 = 'duck';
    System.assertEquals(expectedValue2,response2);
}
}

Sharing is caring!!!!
 
pconpcon
I would really recommend against using the JSON.createParser methods.  It is very difficult to read and debug.  If you do not want to use the typed deserialization you can use untyped deserialization but I would recommend against that too as it can be problematic if the data does not exist as expected.
 
Map<String, Object> jsonData = (Map<String, Object>) JSON.deserializeUntyped(resposne.getBody());
Map<String, Object> animalData = (Map<String, Object>) jsonData.get('animal');
return (String) animalData.get('name');

This does the same thing as the createParser does above (non-typed deserialization) but does it in a manner that is cleaner and easier to read.  In production you'd want to have checks to make sure that the animal key in the jsonData map exists before trying to get the name key.
Siri Chandana LingamguntaSiri Chandana Lingamgunta
Apex Class : 
public class AnimalLocator {
    public static String getAnimalNameById(Integer id){
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint('https://th-apex-http-callout.herokuapp.com/animals/'+id);
        request.setMethod('GET');
        System.debug('>>>>>>>'+id);
        HttpResponse response = http.send(request);
       Object animals; 
        String returnValue; 
        
        // parse the JSON response
        if (response.getStatusCode() == 200) {
            Map<String, Object> result = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
            System.debug('>>>>>'+response.getBody());
            animals = result.get('animal');
            System.debug(animals);
        }
        if (animals != NULL  ) {
            Map<String, Object> result1 = (Map<String, Object>) JSON.deserializeUntyped(JSON.serialize(animals));
            returnValue =(String) result1.get('name');
        }
        return returnValue;
    } 
}

Test Class :
@isTest
global class AnimalLocatorTest {
@isTest static void AnimalLocatorMock1() {
        Test.setMock(HttpCalloutMock.class, new AnimalLocatorMock());
        string result = AnimalLocator.getAnimalNameById(3);
        String expectedResult = 'chicken';
        //System.assertEquals(result,expectedResult );
    }
}
Mock Test : 
@isTest
global class AnimalLocatorMock implements HttpCalloutMock{
     global HTTPResponse respond(HTTPRequest request) {
        // Create a fake response
        HttpResponse response = new HttpResponse();
        response.setHeader('Content-Type', 'application/json');
        response.setBody('{"animal":         {"id":99,"name":"trailhead","eats":"burritos","says":"more badgers"}}');
        response.setStatusCode(200);
        return response; 
    }
}
Ivo Stoykov 9Ivo Stoykov 9
Hi all,

I faced this error and cannot find why it pops up... regardless in the log is visible that the method returns a string as requested. Any idea would be appreciated.

Challenge not yet complete in My Trailhead Playground 2
Executing the 'getAnimalNameById' method on 'AnimalLocator' failed. Make sure the method exists with the name 'getAnimalNameById', is public and static, accepts an Integer and returns a String.

The class
public class AnimalLocator {
    public static String getAnimalNameById(Integer id){
        String uri = 'https://th-apex-http-callout.herokuapp.com/animals/' + id;

        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint(uri);
        request.setMethod('GET');
        System.debug(String.valueOf(request));
        HttpResponse response = http.send(request);
        System.debug(String.valueOf(response));
        Map<String, Object> results = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
        System.debug('results: ' + JSON.serialize(results));
        System.debug('name: ' + results.get('name'));
        return String.valueOf(results.get('name'));

    }
}
The mock
@IsTest
global class AnimalLocatorMock implements HttpCalloutMock {
    
    global HTTPResponse respond(HTTPRequest request){
        System.debug(String.valueOf(this));
        System.debug(String.valueOf(request));
        if(request == null){
            request = new HTTPRequest();
        }
        System.debug(String.valueOf(request));
        HttpResponse response = new HttpResponse();
        System.debug(String.valueOf(response));
        response.setHeader('Content-Type', 'application/json');
        response.setBody('{"id": 1, "name": "Goophy"}');
        response.setStatusCode(200);
        return response; 
    }
}
The test
@IsTest
public class AnimalLocatorTest {

    @IsTest
    public static void getAnimalNameByIdTest(){
    	Test.setMock(HttpCalloutMock.class, new AnimalLocatorMock()); 
        //AnimalsCallouts.makeGetCallout();
        String name = AnimalLocator.getAnimalNameById(1);
        System.assertEquals('Goophy', name);

    }
}

And the log (sorry it is a bit long)
46.0 APEX_CODE,FINEST;APEX_PROFILING,ERROR;CALLOUT,ERROR;DB,INFO;NBA,ERROR;SYSTEM,FINEST;VALIDATION,ERROR;VISUALFORCE,FINE;WAVE,ERROR;WORKFLOW,ERROR
16:41:38.0 (784118)|USER_INFO|[EXTERNAL]|0054I000005d5pV|ivo.stoykov@cunning-wolf-pbmzu5.com|(GMT+01:00) British Summer Time (Europe/London)|GMT+01:00
16:41:38.0 (879221)|EXECUTION_STARTED
16:41:38.0 (884822)|CODE_UNIT_STARTED|[EXTERNAL]|01p4I00000AECnk|AnimalLocatorTest.getAnimalNameByIdTest()
16:41:38.0 (1737787)|HEAP_ALLOCATE|[72]|Bytes:3
16:41:38.0 (1820528)|HEAP_ALLOCATE|[77]|Bytes:152
16:41:38.0 (1842749)|HEAP_ALLOCATE|[342]|Bytes:408
16:41:38.0 (1862952)|HEAP_ALLOCATE|[355]|Bytes:408
16:41:38.0 (1878561)|HEAP_ALLOCATE|[467]|Bytes:48
16:41:38.0 (1912513)|HEAP_ALLOCATE|[139]|Bytes:6
16:41:38.0 (1972860)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:5
16:41:38.0 (2036155)|METHOD_ENTRY|[2]|01p4I00000AECnk|AnimalLocatorTest.AnimalLocatorTest()
16:41:38.0 (2048597)|STATEMENT_EXECUTE|[2]
16:41:38.0 (2055535)|STATEMENT_EXECUTE|[2]
16:41:38.0 (2076167)|METHOD_EXIT|[2]|AnimalLocatorTest
16:41:38.0 (2141099)|HEAP_ALLOCATE|[50]|Bytes:5
16:41:38.0 (2169529)|HEAP_ALLOCATE|[56]|Bytes:5
16:41:38.0 (2179735)|HEAP_ALLOCATE|[64]|Bytes:7
16:41:38.0 (2215660)|STATEMENT_EXECUTE|[5]
16:41:38.0 (2218588)|STATEMENT_EXECUTE|[6]
16:41:38.0 (2222308)|HEAP_ALLOCATE|[6]|Bytes:22
16:41:38.0 (2301423)|HEAP_ALLOCATE|[6]|Bytes:27
16:41:38.0 (2315189)|SYSTEM_METHOD_ENTRY|[1]|Type.Type()
16:41:38.0 (2321764)|STATEMENT_EXECUTE|[1]
16:41:38.0 (2329517)|SYSTEM_METHOD_EXIT|[1]|Type
16:41:38.0 (2338816)|HEAP_ALLOCATE|[6]|Bytes:8
16:41:38.0 (2354273)|HEAP_ALLOCATE|[6]|Bytes:8
16:41:38.0 (2372173)|VARIABLE_SCOPE_BEGIN|[4]|this|System.Type|true|false
16:41:38.0 (2471649)|VARIABLE_ASSIGNMENT|[4]|this|{}|0x1d4c71cf
16:41:38.0 (2483202)|VARIABLE_SCOPE_BEGIN|[4]|apextype|java:common.apex.runtime.ApexObjectType|true|false
16:41:38.0 (2664870)|VARIABLE_ASSIGNMENT|[4]|apextype|"System.HttpCalloutMock"|0x58dd6878
16:41:38.0 (5006082)|HEAP_ALLOCATE|[6]|Bytes:8
16:41:38.0 (7027194)|HEAP_ALLOCATE|[6]|Bytes:1
16:41:38.0 (7045952)|HEAP_ALLOCATE|[6]|Bytes:9
16:41:38.0 (7070980)|METHOD_ENTRY|[2]|01p4I00000AECnp|AnimalLocatorMock.AnimalLocatorMock()
16:41:38.0 (7080331)|STATEMENT_EXECUTE|[2]
16:41:38.0 (7088189)|STATEMENT_EXECUTE|[2]
16:41:38.0 (7093470)|METHOD_EXIT|[2]|AnimalLocatorMock
16:41:38.0 (7111443)|HEAP_ALLOCATE|[6]|Bytes:4
16:41:38.0 (7136345)|CONSTRUCTOR_ENTRY|[6]|01p4I00000AECnp|<init>()|AnimalLocatorMock
16:41:38.0 (7193634)|VARIABLE_SCOPE_BEGIN|[2]|this|AnimalLocatorMock|true|false
16:41:38.0 (7242297)|VARIABLE_ASSIGNMENT|[2]|this|{}|0x48d77269
16:41:38.0 (7269183)|STATEMENT_EXECUTE|[2]
16:41:38.0 (7279490)|CONSTRUCTOR_EXIT|[6]|01p4I00000AECnp|<init>()|AnimalLocatorMock
16:41:38.0 (7336198)|HEAP_ALLOCATE|[6]|Bytes:74
16:41:38.0 (7347508)|SYSTEM_METHOD_ENTRY|[1]|Test.Test()
16:41:38.0 (7352704)|STATEMENT_EXECUTE|[1]
16:41:38.0 (7358911)|SYSTEM_METHOD_EXIT|[1]|Test
16:41:38.0 (7397422)|METHOD_ENTRY|[6]||System.Test.setMock(System.Type, Object)
16:41:38.0 (8426270)|METHOD_EXIT|[6]||System.Test.setMock(System.Type, Object)
16:41:38.0 (8442598)|STATEMENT_EXECUTE|[8]
16:41:38.0 (10296189)|HEAP_ALLOCATE|[8]|Bytes:1
16:41:38.0 (10316841)|HEAP_ALLOCATE|[8]|Bytes:10
16:41:38.0 (10336178)|METHOD_ENTRY|[1]|01p4I00000AECnf|AnimalLocator.AnimalLocator()
16:41:38.0 (10344816)|STATEMENT_EXECUTE|[1]
16:41:38.0 (10350212)|STATEMENT_EXECUTE|[1]
16:41:38.0 (10356848)|METHOD_EXIT|[1]|AnimalLocator
16:41:38.0 (10384251)|METHOD_ENTRY|[8]|01p4I00000AECnf|AnimalLocator.getAnimalNameById(Integer)
16:41:38.0 (10413806)|VARIABLE_SCOPE_BEGIN|[2]|id|Integer|false|false
16:41:38.0 (10437918)|VARIABLE_ASSIGNMENT|[2]|id|1
16:41:38.0 (10453893)|STATEMENT_EXECUTE|[2]
16:41:38.0 (10456516)|STATEMENT_EXECUTE|[3]
16:41:38.0 (10461524)|HEAP_ALLOCATE|[3]|Bytes:51
16:41:38.0 (10513508)|SYSTEM_METHOD_ENTRY|[3]|String.valueOf(Object)
16:41:38.0 (10544193)|HEAP_ALLOCATE|[3]|Bytes:1
16:41:38.0 (10558181)|SYSTEM_METHOD_EXIT|[3]|String.valueOf(Object)
16:41:38.0 (10570895)|HEAP_ALLOCATE|[3]|Bytes:52
16:41:38.0 (10585777)|VARIABLE_SCOPE_BEGIN|[3]|uri|String|false|false
16:41:38.0 (10608436)|VARIABLE_ASSIGNMENT|[3]|uri|"https://th-apex-http (32 more) ..."
16:41:38.0 (10617873)|STATEMENT_EXECUTE|[5]
16:41:38.0 (10637440)|VARIABLE_SCOPE_BEGIN|[5]|http|System.Http|true|false
16:41:38.0 (10709024)|VARIABLE_ASSIGNMENT|[5]|http|"System.Http[]"|0x39b254b9
16:41:38.0 (10718833)|STATEMENT_EXECUTE|[6]
16:41:38.0 (10727234)|VARIABLE_SCOPE_BEGIN|[6]|request|System.HttpRequest|true|false
16:41:38.0 (10767718)|VARIABLE_ASSIGNMENT|[6]|request|"System.HttpRequest[Endpoint=null, Method=null]"|0x5585f791
16:41:38.0 (10776900)|STATEMENT_EXECUTE|[7]
16:41:38.0 (10818322)|SYSTEM_METHOD_ENTRY|[7]|System.HttpRequest.setEndpoint(String)
16:41:38.0 (10839089)|SYSTEM_METHOD_EXIT|[7]|System.HttpRequest.setEndpoint(String)
16:41:38.0 (10845705)|STATEMENT_EXECUTE|[8]
16:41:38.0 (10850079)|HEAP_ALLOCATE|[8]|Bytes:3
16:41:38.0 (10864275)|SYSTEM_METHOD_ENTRY|[8]|System.HttpRequest.setMethod(String)
16:41:38.0 (10876926)|SYSTEM_METHOD_EXIT|[8]|System.HttpRequest.setMethod(String)
16:41:38.0 (10882605)|STATEMENT_EXECUTE|[9]
16:41:38.0 (10906094)|SYSTEM_METHOD_ENTRY|[9]|String.valueOf(Object)
16:41:38.0 (10919467)|HEAP_ALLOCATE|[9]|Bytes:93
16:41:38.0 (10932196)|SYSTEM_METHOD_EXIT|[9]|String.valueOf(Object)
16:41:38.0 (10951547)|SYSTEM_METHOD_ENTRY|[9]|System.debug(ANY)
16:41:38.0 (10965253)|USER_DEBUG|[9]|DEBUG|System.HttpRequest[Endpoint=https://th-apex-http-callout.herokuapp.com/animals/1, Method=GET]
16:41:38.0 (10974996)|SYSTEM_METHOD_EXIT|[9]|System.debug(ANY)
16:41:38.0 (10980976)|STATEMENT_EXECUTE|[10]
16:41:38.0 (10989002)|SYSTEM_METHOD_ENTRY|[10]|System.Http.send(ANY)
16:41:38.0 (11175854)|HEAP_ALLOCATE|[10]|Bytes:4
16:41:38.0 (11191822)|HEAP_ALLOCATE|[10]|Bytes:52
16:41:38.0 (11202981)|VARIABLE_SCOPE_BEGIN|[4]|this|AnimalLocatorMock|true|false
16:41:38.0 (11233704)|VARIABLE_ASSIGNMENT|[4]|this|{}|0x48d77269
16:41:38.0 (11245013)|VARIABLE_SCOPE_BEGIN|[4]|request|System.HttpRequest|true|false
16:41:38.0 (11301351)|VARIABLE_ASSIGNMENT|[4]|request|"System.HttpRequest[Endpoint=https://th-apex-http-callout.herokuapp.com/animals/1, Method=GET]"|0x5585f791
16:41:38.0 (11330358)|STATEMENT_EXECUTE|[4]
16:41:38.0 (11333115)|STATEMENT_EXECUTE|[5]
16:41:38.0 (11350024)|SYSTEM_METHOD_ENTRY|[5]|String.valueOf(Object)
16:41:38.0 (11367494)|HEAP_ALLOCATE|[5]|Bytes:20
16:41:38.0 (11376662)|SYSTEM_METHOD_EXIT|[5]|String.valueOf(Object)
16:41:38.0 (11385429)|SYSTEM_METHOD_ENTRY|[5]|System.debug(ANY)
16:41:38.0 (11390797)|USER_DEBUG|[5]|DEBUG|AnimalLocatorMock:[]
16:41:38.0 (11396730)|SYSTEM_METHOD_EXIT|[5]|System.debug(ANY)
16:41:38.0 (11401035)|STATEMENT_EXECUTE|[6]
16:41:38.0 (11408931)|SYSTEM_METHOD_ENTRY|[6]|String.valueOf(Object)
16:41:38.0 (11416809)|HEAP_ALLOCATE|[6]|Bytes:93
16:41:38.0 (11426772)|SYSTEM_METHOD_EXIT|[6]|String.valueOf(Object)
16:41:38.0 (11433190)|SYSTEM_METHOD_ENTRY|[6]|System.debug(ANY)
16:41:38.0 (11437269)|USER_DEBUG|[6]|DEBUG|System.HttpRequest[Endpoint=https://th-apex-http-callout.herokuapp.com/animals/1, Method=GET]
16:41:38.0 (11442883)|SYSTEM_METHOD_EXIT|[6]|System.debug(ANY)
16:41:38.0 (11447391)|STATEMENT_EXECUTE|[7]
16:41:38.0 (11450173)|STATEMENT_EXECUTE|[10]
16:41:38.0 (11457856)|SYSTEM_METHOD_ENTRY|[10]|String.valueOf(Object)
16:41:38.0 (11465388)|HEAP_ALLOCATE|[10]|Bytes:93
16:41:38.0 (11473165)|SYSTEM_METHOD_EXIT|[10]|String.valueOf(Object)
16:41:38.0 (11478909)|SYSTEM_METHOD_ENTRY|[10]|System.debug(ANY)
16:41:38.0 (11483001)|USER_DEBUG|[10]|DEBUG|System.HttpRequest[Endpoint=https://th-apex-http-callout.herokuapp.com/animals/1, Method=GET]
16:41:38.0 (11488496)|SYSTEM_METHOD_EXIT|[10]|System.debug(ANY)
16:41:38.0 (11492349)|STATEMENT_EXECUTE|[11]
16:41:38.0 (11506700)|VARIABLE_SCOPE_BEGIN|[11]|response|System.HttpResponse|true|false
16:41:38.0 (11544143)|VARIABLE_ASSIGNMENT|[11]|response|"System.HttpResponse[Status=null, StatusCode=0]"|0x2a495d47
16:41:38.0 (11550648)|STATEMENT_EXECUTE|[12]
16:41:38.0 (11559899)|SYSTEM_METHOD_ENTRY|[12]|String.valueOf(Object)
16:41:38.0 (11569095)|HEAP_ALLOCATE|[12]|Bytes:46
16:41:38.0 (11577460)|SYSTEM_METHOD_EXIT|[12]|String.valueOf(Object)
16:41:38.0 (11583988)|SYSTEM_METHOD_ENTRY|[12]|System.debug(ANY)
16:41:38.0 (11588286)|USER_DEBUG|[12]|DEBUG|System.HttpResponse[Status=null, StatusCode=0]
16:41:38.0 (11593748)|SYSTEM_METHOD_EXIT|[12]|System.debug(ANY)
16:41:38.0 (11597735)|STATEMENT_EXECUTE|[13]
16:41:38.0 (11601553)|HEAP_ALLOCATE|[13]|Bytes:12
16:41:38.0 (11606472)|HEAP_ALLOCATE|[13]|Bytes:16
16:41:38.0 (11629778)|SYSTEM_METHOD_ENTRY|[13]|System.HttpResponse.setHeader(String, String)
16:41:38.0 (11656148)|SYSTEM_METHOD_EXIT|[13]|System.HttpResponse.setHeader(String, String)
16:41:38.0 (11661187)|STATEMENT_EXECUTE|[14]
16:41:38.0 (11664819)|HEAP_ALLOCATE|[14]|Bytes:27
16:41:38.0 (11674815)|SYSTEM_METHOD_ENTRY|[14]|System.HttpResponse.setBody(String)
16:41:38.0 (11700369)|SYSTEM_METHOD_EXIT|[14]|System.HttpResponse.setBody(String)
16:41:38.0 (11704885)|STATEMENT_EXECUTE|[15]
16:41:38.0 (11718178)|SYSTEM_METHOD_ENTRY|[15]|System.HttpResponse.setStatusCode(Integer)
16:41:38.0 (11727560)|SYSTEM_METHOD_EXIT|[15]|System.HttpResponse.setStatusCode(Integer)
16:41:38.0 (11731592)|STATEMENT_EXECUTE|[16]
16:41:38.0 (11746146)|HEAP_ALLOCATE|[10]|Bytes:31
16:41:38.0 (11752163)|SYSTEM_METHOD_EXIT|[10]|System.Http.send(ANY)
16:41:38.0 (11757500)|VARIABLE_SCOPE_BEGIN|[10]|response|System.HttpResponse|true|false
16:41:38.0 (11787139)|VARIABLE_ASSIGNMENT|[10]|response|"System.HttpResponse[Status=null, StatusCode=200]"|0x2a495d47
16:41:38.0 (11793518)|STATEMENT_EXECUTE|[11]
16:41:38.0 (11805494)|SYSTEM_METHOD_ENTRY|[11]|String.valueOf(Object)
16:41:38.0 (11815090)|HEAP_ALLOCATE|[11]|Bytes:48
16:41:38.0 (11823379)|SYSTEM_METHOD_EXIT|[11]|String.valueOf(Object)
16:41:38.0 (11830320)|SYSTEM_METHOD_ENTRY|[11]|System.debug(ANY)
16:41:38.0 (11834743)|USER_DEBUG|[11]|DEBUG|System.HttpResponse[Status=null, StatusCode=200]
16:41:38.0 (11840518)|SYSTEM_METHOD_EXIT|[11]|System.debug(ANY)
16:41:38.0 (11844310)|STATEMENT_EXECUTE|[12]
16:41:38.0 (11851314)|SYSTEM_METHOD_ENTRY|[12]|System.HttpResponse.getBody()
16:41:38.0 (11865468)|HEAP_ALLOCATE|[12]|Bytes:27
16:41:38.0 (11870102)|SYSTEM_METHOD_EXIT|[12]|System.HttpResponse.getBody()
16:41:38.0 (11927199)|HEAP_ALLOCATE|[12]|Bytes:24
16:41:38.0 (11941330)|SYSTEM_METHOD_ENTRY|[1]|JSON.JSON()
16:41:38.0 (11948486)|STATEMENT_EXECUTE|[1]
16:41:38.0 (11960611)|SYSTEM_METHOD_EXIT|[1]|JSON
16:41:38.0 (11977163)|METHOD_ENTRY|[12]||System.JSON.deserializeUntyped(String)
16:41:38.0 (12273201)|METHOD_EXIT|[12]||System.JSON.deserializeUntyped(String)
16:41:38.0 (12288405)|VARIABLE_SCOPE_BEGIN|[12]|results|Map<String,ANY>|true|false
16:41:38.0 (12321238)|VARIABLE_ASSIGNMENT|[12]|results|{"id":1,"name":"Goophy"}|0x5e801fbb
16:41:38.0 (12330918)|STATEMENT_EXECUTE|[13]
16:41:38.0 (12335059)|HEAP_ALLOCATE|[13]|Bytes:9
16:41:38.0 (12351546)|METHOD_ENTRY|[13]||System.JSON.serialize(Object)
16:41:38.0 (12893985)|METHOD_EXIT|[13]||System.JSON.serialize(Object)
16:41:38.0 (12911420)|HEAP_ALLOCATE|[13]|Bytes:33
16:41:38.0 (12923754)|SYSTEM_METHOD_ENTRY|[13]|System.debug(ANY)
16:41:38.0 (12929794)|USER_DEBUG|[13]|DEBUG|results: {"name":"Goophy","id":1}
16:41:38.0 (12936567)|SYSTEM_METHOD_EXIT|[13]|System.debug(ANY)
16:41:38.0 (12941665)|STATEMENT_EXECUTE|[14]
16:41:38.0 (12946185)|HEAP_ALLOCATE|[14]|Bytes:6
16:41:38.0 (12951728)|HEAP_ALLOCATE|[14]|Bytes:4
16:41:38.0 (12978519)|SYSTEM_METHOD_ENTRY|[14]|Map<String,ANY>.get(Object)
16:41:38.0 (13001804)|SYSTEM_METHOD_EXIT|[14]|Map<String,ANY>.get(Object)
16:41:38.0 (13017548)|SYSTEM_METHOD_ENTRY|[14]|String.valueOf(Object)
16:41:38.0 (13024546)|HEAP_ALLOCATE|[14]|Bytes:6
16:41:38.0 (13042905)|SYSTEM_METHOD_EXIT|[14]|String.valueOf(Object)
16:41:38.0 (13054909)|HEAP_ALLOCATE|[14]|Bytes:12
16:41:38.0 (13069464)|SYSTEM_METHOD_ENTRY|[14]|System.debug(ANY)
16:41:38.0 (13083864)|USER_DEBUG|[14]|DEBUG|name: Goophy
16:41:38.0 (13095914)|SYSTEM_METHOD_EXIT|[14]|System.debug(ANY)
16:41:38.0 (13105151)|STATEMENT_EXECUTE|[15]
16:41:38.0 (13118446)|SYSTEM_METHOD_ENTRY|[15]|Map<String,ANY>.get(Object)
16:41:38.0 (13147524)|SYSTEM_METHOD_EXIT|[15]|Map<String,ANY>.get(Object)
16:41:38.0 (13173032)|SYSTEM_METHOD_ENTRY|[15]|String.valueOf(Object)
16:41:38.0 (13180739)|HEAP_ALLOCATE|[15]|Bytes:6
16:41:38.0 (13203231)|SYSTEM_METHOD_EXIT|[15]|String.valueOf(Object)
16:41:38.0 (13213673)|METHOD_EXIT|[8]|01p4I00000AECnf|AnimalLocator.getAnimalNameById(Integer)
16:41:38.0 (13223015)|VARIABLE_SCOPE_BEGIN|[8]|name|String|false|false
16:41:38.0 (13243471)|VARIABLE_ASSIGNMENT|[8]|name|"Goophy"
16:41:38.0 (13251930)|STATEMENT_EXECUTE|[9]
16:41:38.0 (13258044)|HEAP_ALLOCATE|[9]|Bytes:6
16:41:38.0 (13286131)|SYSTEM_METHOD_ENTRY|[9]|System.assertEquals(ANY, ANY)
16:41:38.0 (13328932)|SYSTEM_METHOD_EXIT|[9]|System.assertEquals(ANY, ANY)
16:41:38.0 (13356449)|CODE_UNIT_FINISHED|AnimalLocatorTest.getAnimalNameByIdTest()
16:41:38.0 (14580480)|EXECUTION_FINISHED



 
BenitoVBenitoV
I think the reason is the structure of the JSON, it must look like this one:
{ "animal": { "id": 1, "name": "chicken", "eats": "chicken food", "says": "cluck cluck" } }

And you need to change the code to parse it corretly.
Jennifer Do 9Jennifer Do 9

{ "animal": { "id": 1, "name": "chicken", "eats": "chicken food", "says": "cluck cluck" } }

this worked for me too!

NipuWNipuW
Following worked for me. Here i am not using JSON parser or JSON.deserialize() with a seperate mapping class. But simply using another Map to get the inner object by name. 

public class AnimalLocator {
    
    public static String getAnimalNameById(Integer animalId) {
        String animalName;
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint('https://th-apex-http-callout.herokuapp.com/animals/'+animalId);
        request.setMethod('GET');
        HttpResponse response = http.send(request);
        // If the request is successful, parse the JSON response.
        if (response.getStatusCode() == 200) {
            // Deserializes the JSON string into collections of primitive data types.
            Map<String, Object> animalList = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
            Map<String, Object> animal = (Map<String, Object>) animalList.get('animal');
            animalName =  (String)animal.get('name');   
            System.debug(animalList);
        }
        return animalName;
    }

nikolai calder 14nikolai calder 14
Keep getting an error in trailhead even though my test has no failure someone please help
here is the code 
 
public class AnimalLocator {
    public static String getAnimalById(Integer num){
        String animalName;
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint('https://th-apex-http-callout.herokuapp.com/animals/'+num);
        request.setMethod('GET');
        HttpResponse response = http.send(request);
        if (response.getStatusCode() == 200) {
            Map<String, Object> r = (Map<String, Object>)
                JSON.deserializeUntyped(response.getbody());
            Map<String, Object> animal = (Map<String, Object>)r.get('animal');
            animalName = string.valueof(animal.get('name'));
            
        }
        return animalName;
    }
}



@isTest
global class AnimalLocatorMock implements HttpCalloutMock {
    // Implement this interface method
    global HTTPResponse respond(HTTPRequest request) {
        // Create a fake response
        HttpResponse response = new HttpResponse();
        response.setHeader('Content-Type', 'application/json');
        response.setBody('{"animal":{"id":1,"name":"chicken","eats":"chicken food","says":"cluck cluck"}}');
        response.setStatusCode(200);
        return response; 
    }
}



@isTest
private class AnimalLocatorTest{
@isTest static void getAnimalByIdTest () {
    // Set mock callout class 
    Test.setMock(HttpCalloutMock.class, new AnimalLocatorMock()); 
    // This causes a fake response to be sent
    // from the class that implements HttpCalloutMock. 
    String response = AnimalLocator.getAnimalById(1);
    System.assertEquals('chicken', response);
}
    }

 
nikolai calder 14nikolai calder 14
i'll leave my original question up but i finally figured it out. The problem was that because I stayed up late working on this, my brain decided not to notice the correct naming of the method is getAnimalNameById and not getAnimalById XD. Feel free to use and improve upon my original post.