API Calls

Let's deal with some more complicated JSONs today. Use Postman to make a call to https://admin2dev.com/rest/response3.json

{
	"Name": {
		"firstName": "John",
		"lastName": "Smith"
	},
	"Deals": [
		{
			"Name": "Opportunity Name",
			"CloseDate": "03022020",
			"Amount": 2200
		},
		{
			"Name": "Opportunity 2 Name",
			"CloseDate": "03122020",
			"Amount": 3000
		},
		{
			"Name": "Opportunity 3 Name",
			"CloseDate": "12062020",
			"Amount": 800
		}
	],
	"Account": "GenePoint"
}

Now we have a complicated JSON file here, given we have an object, a key value pair and an array in our top level. Let's focus on just writing the classes for this JSON here.

First, we deal with the Account key value pair. Since it's on the top level with no objects, we can directly define it as a String.

public class JSONResponse{
	public String Account;
}

Now, let's deal with the Name object that has two key value pairs named firstName and lastName. We know how to deal with this, make a new class with the name Name and in our JSONResponse class, define a variable with Name class.

public class JSONResponse{
	public String Account;
	public Name name;
}

public class Name{
	public String firstName, lastName;
}

Now dealing with arrays is simple, we define a new class, the same way we would for an object but in our JSONResponse when we declare a variable of that class type, we declare it as a List<ClassName>. Let's take a look:

public class JSONResponse{
	public String Account;
	public Name name;
	public List<Deals> deals;
}

public class Name{
	public String firstName, lastName;
}

public class Deals{
	public String Name, CloseDate;
	public Integer Amount;
}

Our JSON Structure is done! Now when we want to access values inside the Deals array, we would access it the same way as we would with a List. To return the Amount for Opportunity 2 Name we would:

return response.Deals[1].Amount;

and change the return type of our methodName() to Integer instead of String. Here's the full class:

public class ComplexResponseClass {

    public class JSONResponse { //create JSON structure class
        public Name name;
        public List<Deals> deals;
        public String Account;
    }

    public class Name{
        public String firstName, lastName;
    }
    public class Deals{
        public String name, CloseDate;
        public Integer amount;
    }

    public static Integer methodName() {

        //Make the Request and save it

        String requestURL = 'https://admin2dev.com/rest/response3.json';
        String requestType = 'GET'; //GET POST PATCH PUT DELETE

        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint(requestURL);
        request.setMethod(requestType);
        HttpResponse response = http.send(request);

        // Deserialize based on result type class
        JSONResponse result = (JSONResponse) JSON.deserialize(response.getBody(), JSONResponse.class);
        return result.Deals[1].Amount;

    }
}

Test and Mock Class

Writing test classes for API calls is a little different than writing tests for other classes. There's an additional class that must be written, called the Mock Class. A mock class is a class that simulates a JSON response because Test classes aren't allowed to make HTTP Calls.

First, let's look at Mock Class for the class we just wrote

Mock Class

First, open Postman and make an API Call. Now change the preview to Preview so it looks something like this:

Copy the whole JSON that's now in a single line. Now let's get down to writing our Mock Class.

First, make a test class that implements HttpCalloutMock

@isTest
global class ComplexResponseCLassMock implements HttpCalloutMock{

}

Now, we need to build a response. For this, we create a new method that returns HTTPResponse and takes a HTTPRequest as an input parameter:

@isTest
global class ComplexResponseClassMock implements HttpCalloutMock{
	global HTTPResponse respond(HTTPRequest request){
	}

}

Now we build our response and return it. For this, we create a new variable of HttpResponse type and use .setStatusCode() and .setBody() to set the code and JSON, and then return it:

@isTest
global class ComplexResponseClassMock implements HttpCalloutMock {
	global HTTPResponse respond(HTTPRequest request) {

        HttpResponse response = new Httpresponse();
        response.setStatusCode(200);
        response.setBody('JSON IN ONE LINE GOES HERE'); //This is what the mock repsonse will be
        return response;
    }

}

A status code of 200 means the request was successful and everything went as it should You can read more about it on Mozilla Developer Network. Now let's create a new string and store our JSON and set that variable in response.setBody() to make our code easy to understand and create a snippet:

@isTest
global class ComplexResponseClassMock implements HttpCalloutMock {
	global HTTPResponse respond(HTTPRequest request) {

        HttpResponse response = new Httpresponse();
        String responseJSON = '{ "Name": { "firstName": "John", "lastName": "Smith" }, "Deals": [{ "Name": "Opportunity Name", "CloseDate": "03022020", "Amount": 2200 }, { "Name": "Opportunity 2 Name", "CloseDate": "03122020", "Amount": 3000 }, { "Name": "Opportunity 3 Name", "CloseDate": "12062020", "Amount": 800 } ], "Account": "GenePoint" }';


        response.setStatusCode(200);
        response.setBody(responseJSON); //This is what the mock repsonse will be
        return response;
    }

}

The value for responseJSON is simply what we want this class to return. A good practice is to copy an example response and build test class on it. Now a snippet for making a mock response class would be:

@isTest
global class ClassNameMock implements HttpCalloutMock {
	global HTTPResponse respond(HTTPRequest request) {

        HttpResponse response = new Httpresponse();
        String responseJSON = 'JSON in one line goes here';
        response.setStatusCode(200);
        response.setBody(responseJSON); //This is what the mock repsonse will be
        return response;
    }

}

Now let's write our test class:

Test Class

For our tester class, we simply call the mock response class

@isTest
public class ComplexResponseTest {
    static testmethod void testerClass(){

        Test.setMock(HttpCalloutMock.class, new ComplexResponseClassMock()); //This line makes the call to mock response class
        //No Test.start / end necessary
        System.assertEquals('03022020', ComplexResponseClass.methodName()); //Verify the values are correct

    }

}

A quick breakdown:

  • Define a Test class
  • Define a testmethod
    • Call the mock class by making a new instance of the class by using Test.setMock(HttpCalloutMock.class, ew ComplexResponseClassMock());

A snippet for this would be:

@isTest
public class myClassTest {
    static testmethod void testerClass(){

        Test.setMock(HttpCalloutMock.class, new ClassMock()); //Replace ClassMock with the Mock Class Name

    }

}

And that's it! Now we run the test class and verify code coverage.

Summary

  • Every API Call must have a Mock and Test Class
  • A Mock Class simulates a valid API response
  • A Test Class calls the Mock Class and verifies values by calling the main class.
Day 24: REST API Class, Mock Class and Test Class Test