img1

Prologue

The Salesforce platform offers different sets of integration capabilities that enable you to tightly integrate your Apex code with an external service. This feat is possible through three features dubbed callouts:

  • Apex Rest Callout
  • Apex SOAP Callout
  • Apex Web Service

Note: Web service callouts to SOAP web services use XML, and typically require a WSDL document for code generation. HTTP callouts to services typically use REST with JSON. Before any Apex callout can invoke an external site, that site must be registered in the Remote Site Settings page, or the callout will fail.

Remote Sites

To able to integrate with external services, each service endpoint must be linked to a remote site in Salesforce. To create a Remote site follow the steps below.

  1. From Setup, enter Remote Site Settings in the Quick Find box, then click Remote Site Settings.
  2. Click New Remote Site.
  3. Enter the site name.
  4. Enter the site URL.
  5. Click Save.

Apex REST Callouts

The fundamental concept in any RESTful API is the resource. A resource is an object with a type, associated data, relationships to other resources, and a set of methods that operate on it. A REST request consists of four components: a resource URI, an HTTP method, request headers, and a request body. Each resource can be accessed using standard HTTP methods, for example (HEAD, GET, POST, PATCH, DELETE). Request headers specify metadata for the request. The request body specifies data for the request.

Apex REST Callout Examples

Requirement: Please create a Remote Site with the following URL https://jsonplaceholder.typicode.com and name TestCallout. Just for testing purposes, delete after.

Get Data from a Service

The following snippet queries the supplied comments endpoint for the post with id = 5, firstly the array of comments are deserialized. we then deserialize each comment only if the response was successful.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
String url = 'https://jsonplaceholder.typicode.com/posts/5/comments';
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndPoint(url);
request.setMethod('GET');
HttpResponse response = http.send(request);

if(response.getStatusCode() == 200){
     List<Object> results = (List<Object>)JSON.deserializeUntyped(response.getBody());
    for(Object record: results){
        Map<String,Object> result = (Map<String,Object>)record;
        System.debug(result);
    }
}

Send Data to a Service

The code snippet below creates a new resource using the following url.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
String url = 'https://jsonplaceholder.typicode.com/posts';
Http http  = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint(url);
request.setMethod('POST');
request.setHeader('ContentType','application/json;charset=UTF-8;');

// used to create JSON object
JSONGenerator gen = JSON.createGenerator(true);
gen.writeStartObject();
gen.writeStringField('title','Create Content');
gen.writeStringField('userId','1');
gen.writeStringField('body','Awesome generated content!');
gen.writeEndObject();
request.setBody(gen.getAsString());

HttpResponse response = http.send(request);
if(response.getStatusCode() == 201){
    System.debug(response.getBody());
} else {
    System.debug('The status code returned was not expected: ' + response.getStatusCode() + ' ' + response.getStatus());
}

Let us put it all together in one class called FakePostCallouts.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class FakePostCallouts {
    public static void callGetCallout(){
        String url = 'https://jsonplaceholder.typicode.com/posts/5/comments';
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndPoint(url);
        request.setMethod('GET');
        HttpResponse response = http.send(request);

        if(response.getStatusCode() == 200){
            List<Object> results = (List<Object>)JSON.deserializeUntyped(response.getBody());
            for(Object record: results){
                Map<String,Object> result = (Map<String,Object>)record;
                System.debug(result);
            }
        } else {
            System.debug('The status code returned was not expected: ' + response.getStatusCode() + ' ' + response.getStatus());
        }
    }
    public static void callPostCallout(){
        String url = 'https://jsonplaceholder.typicode.com/posts';
        Http http  = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint(url);
        request.setMethod('POST');
        request.setHeader('ContentType','application/json;charset=UTF-8;');

        // used to create JSON object
        JSONGenerator gen = JSON.createGenerator(true);
        gen.writeStartObject();
        gen.writeStringField('title','Create Content');
        gen.writeStringField('userId','1');
        gen.writeStringField('body','Awesome generated content!');
        gen.writeEndObject();
        request.setBody(gen.getAsString());

        HttpResponse response = http.send(request);
        if(response.getStatusCode() == 201){
            System.debug(response.getBody());
        } else {
            System.debug('The status code returned was not expected: ' + response.getStatusCode() + ' ' + response.getStatus());
        }
    }
}

Testing REST Callouts

Apex test methods don’t support callouts, and tests that perform callouts fail. To remedy this plight, the testing runtime allows you to “mock” the callout. Mock callouts allow you to specify the response to return in the test instead of actually calling the web service. You can mock callouts either by implementing the HttpCalloutMock interface or using static resources.

Test a Callout with HttpCalloutMock

This interface enables you to specify the response that’s sent in the respond method. Your test class instructs the Apex runtime to send this fake response by calling Test.setMock again. The class implementing this interface must be annotated with the @isTest annotation.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@isTest
global class FakePostCalloutsMock implements HttpCalloutMock {
    // Implement this interface method
    public HttpResponse respond(HttpRequest request){
        //create fake response
        HttpResponse response = new HttpResponse();
        response.setHeader('Content-Type', 'application/json;charset=UTF-8;');
        // used to create JSON object
        JSONGenerator gen = JSON.createGenerator(true);
        gen.writeStartObject();
        gen.writeStringField('title','Create Content');
        gen.writeStringField('userId','1');
        gen.writeStringField('id','101');
        gen.writeStringField('body','Awesome generated content!');
        gen.writeEndObject();
        response.setBody(gen.getAsString());
        reponse.setStatusCode(201);
        return response;
    }
}

Testing FakePostCalloutsMock using FakePostCalloutsMock requires one important step to be done:

  • Call Test.setMoock(HttpCalloutMock.class, new FakePostCalloutsMock()); top level in your test class
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@isTest
public FakeCalloutTests {

    @isTest
    public static void testCallPostCallout(){
        // Set mock callout class , causes the fake response to be sent
        Test.setMock(HttpCalloutMock.class, new FakePostCalloutsMock());
        HttpResponse response = FakePostCallouts.callPostCallout();
        System.assertEquals(200, response.getStatusCode());
        System.assert(response.getHeader('Content-Type') == 'application/json');
        String actualValue = response.getBody();
        System.assert(actualValue.contains('101'));
    }
}

Apex SOAP Callouts

In addition to REST callouts, Apex can also make callouts to SOAP web services using XML. Soap callouts are contingent on a WSDL document. Web Services Description Language (WSDL) is an XML-based file that basically tells the client application what the web service does. The WSDL file is used to describe in a nutshell what the web service is capable of and provide the client with all the information required to connect to the web service and use all the functionality provided by the web service.

Note: Use outbound messaging to handle integration solutions when possible. Use callouts to third-party web services only when necessary.

Note: WSDL2Apex automatically generates Apex classes from a WSDL document. You download the web service’s WSDL file, and then you upload the WSDL and WSDL2Apex generates the Apex classes for you. The Apex classes construct the SOAP XML, transmit the data, and parse the response XML into Apex objects. Instead of developing the logic to construct and parse the XML of the web service messages, let the Apex classes generated by WSDL2Apex internally handle all that overhead. Code examples wont be provided in this article for Soap Web Services.

Epilogue

The moral from this article was to ease your introduction towards the various Integration services Salesforce has to offer. Rest Callout was discussed, specifically how to retrieve resources from a external service and how to create resources. Various testing examples were also demonstrated, such as Callout mocking and actual apex testing. SOAP Callouts and Platform Integration Services will be subsequently covered in part 2 and 3 in this series. Thanks for stopping by and I hope you were able to learn or reinforce your knowledge regarding Rest Callouts on the Salesforce platform 😃