Saturday, December 4, 2021

How to make callout from batch class in salesforce?

Yes it possible to do callouts from batch apex in Salesforce. To make callouts from batch apex ensure that your Batch Apex class implements the Database.AllowsCallouts interface. This interface allows the batch job to make callouts.

global class YourBatchClass implements Database.Batchable<SObject>, Database.AllowsCallouts {

    // Batch Apex logic here

}

In this tutorial, we will guide you through the process of making callouts from Batch Apex in Salesforce. We will focus on scenario where the external system is also Salesforce, demonstrating how to leverage the power of Batch Apex to streamline communication between Salesforce environments.

In this batch class, our mission is to efficiently fetch all contacts where the custom field 'SFDCID__c' is not null. Once identified, we'll seamlessly transmit this curated set of contacts to an external Salesforce system.

Note: Start, execute, and finish methods can implement up to 100 callouts each.

Batch Class Created in ORG A:

In the start method of batch class , we are doing a callout to ORG B token URL to get the access token and then this access token will be used in execute method to send the POST call to ORG B for contact creation.

global class BatchApexCalloutClass implements Database.Batchable < sObject > ,   Database.AllowsCallouts, Database.Stateful {

    public String query = 'Select ID,FirstName,LastName,Email,SFDCID__c from Contact Where SFDCID__c!= null';

    global String accToken;

    global String instanceurl;

    public class responseWrapper {

    public string id;

    public string access_token;

    public string instance_url;

    }

    List < Contact > updatedConList = new List < Contact > ();

    global Database.QueryLocator start(Database.BatchableContext BC) {

        String endpointthirdpartysystem = 'https: //farukh-dev-ed.my.salesforce.com/services/oauth2/token';

        String cKey;

        String cSecret;

        List < Store_Cred__mdt > connectionParam = [SELECT Id, MasterLabel, client_id__c, client_secret__c, username__c, password__c from Store_Cred__mdt];

        if (connectionParam.size() > 0) {

            cKey = connectionParam[0].client_id__c;

            cSecret = connectionParam[0].client_secret__c;

        }

        System.debug('Store_Cred__mdt' + connectionParam);

        string reqBody = 'grant_type=client_credentials&client_id=' + cKey + '&client_secret=' + cSecret;

        Http h = new Http();

        HttpRequest req = new HttpRequest();

        req.setBody(reqBody);

        req.setMethod('POST');

        req.setEndpoint('https://farukh-dev-ed.my.salesforce.com/services/oauth2/token');

        HttpResponse hresp = h.send(req);

        responseWrapper wResp = (responseWrapper) JSON.deserialize(hresp.getBody(), responseWrapper.class);

        accToken = wResp.access_token;

        instanceurl = wResp.instance_url;

        System.debug('accToken' + accToken);

        System.debug('instanceurl' + instanceurl);

        return Database.getQueryLocator(query);

    }

    global void execute(Database.BatchableContext BC, List < Contact > conList) {

        System.debug('Inside Execute Method');

        System.debug('accToken' + accToken);

        System.debug('instanceurl' + instanceurl);

        System.debug('conListSize' + conList.size());

        for (integer i = 0; i < conList.size(); i++) {

            try {

                if (accToken != '') {

                    string endPoint = instanceurl + '/services/apexrest/createContactRecordWebservice';

                    Http h1 = new Http();

                    HttpRequest req1 = new HttpRequest();

                    req1.setHeader('Authorization', 'Bearer ' + accToken);

                    req1.setHeader('Content-Type', 'application/json');

                    req1.setMethod('POST');

                    req1.setEndpoint(endPoint);

                    system.debug('conList[i]' + conList[i]);

                    req1.setBody(JSON.serialize(conList[i]));

                    HttpResponse hresp1 = h1.send(req1);

                    system.debug('hresp1' + hresp1);

                    system.debug('hresp1.getStatusCode()' + hresp1.getStatusCode());

                    system.debug('hresp1.getBody()' + hresp1.getBody());

                    if (hresp1.getStatusCode() == 200) {

                        system.debug('Callout Success');

                    }

                }

            } catch (Exception e) {

                System.debug('Some error occured and is : ' + e.getMessage() + 'at line number: ' + e.getLineNumber());

            }

        }

    }

    global void finish(Database.BatchableContext BC) {}

}

Webservice Class Created in ORG B:

The below Webservice in ORG B will be invoked from the execute method of the batch class from ORG A. It is expecting First Name, Last Name, Email in the request body and it will then create contact record.

@RestResource(urlMapping = '/createContactRecordWebservice/*')

global with sharing class createContactRecord {

  @HTTPPOST

  global static boolean insertContact() {

    Boolean finalStatus;

    RestRequest req = RestContext.request;

    system.debug('RestContext.request' + RestContext.request);

    RestResponse res = Restcontext.response;

    Map < String, Object > newmap = (Map < String, Object > ) JSON.deserializeUntyped(req.requestBody.toString());

    system.debug('newmap ' + newmap);

    String fName = (String) newmap.get('FirstName');

    system.debug('fName' + fName);

    String lName = (String) newmap.get('LastName');

    String email = (String) newmap.get('Email');

    Contact con = new Contact();

    con.FirstName = fName;

    con.LastName = lName;

    con.Email = email;

 

    /***Modify the HTTP status code that will be returned to external system***/

    try {

      insert con;

      res.statuscode = 201;

      finalStatus = true;

    }

    /***Modify the HTTP status code that will be returned to external system***/

    catch (Exception e) {

      System.debug('Some error occured and is : ' + e.getMessage() + 'at line number: ' + e.getLineNumber());

      finalStatus = false;

    }

    return finalStatus;

 

  }

 

}

Now, we will create a CSV file of contact records and will try to load more than 100 contacts in ORG A to check the batch apex working.

How to make callout from batch class in salesforce?

Now, let us try to execute the below code from anonymous window. Note in the below example we are not passing the scope size.

BatchApexCalloutClass batchObject = new BatchApexCalloutClass();

 

Id batchId = Database.executeBatch(batchObject);


How to make callout from batch class in salesforce?

As we have loaded more than 100 contact records, and when we execute the above code from an anonymous window, we will get the error as shown in the below image. This is because when we do not specify the scope size, 200 is taken as the default, and since we will get more than 100 records in a batch, the number of callouts will exceed the 100 limit.

How to make callout from batch class in salesforce?

Now, let’s specify the scope size as 100 as shown in below image.

How to make callout from batch class in salesforce?

Now, the code will be successfully executed.

How to make callout from batch class in salesforce?

As the batch is successfully executed, we can also see the records will be successfully created in ORG B.

How to make callout from batch class in salesforce?

Looking to Master Batch Apex Essential? Have a look at the course specially designed to Master Batch Apex.


Throughout the course, we'll delve into crucial subjects such as understanding Batch Apex's role, controlling batch size, harnessing the power of Database.Stateful, executing callouts, implementing best practices, exploring limitations, triggering batch classes from apex triggers, mastering future methods, and comprehending queueable Apex. Additionally, we'll discuss advanced concepts like chaining Batch Jobs and dissect real-world scenarios where Batch Apex proves invaluable.

Here's a glimpse of the comprehensive table of contents:

        1) What is Batch Apex in Salesforce?
        2) How to control number of batches in Batch Apex using scope size?
        3) What is Database.Stateful in Batch Apex in Salesforce?
        4) How to do callouts from Batch Apex in Salesforce?
        5) What are Salesforce batch apex best practices?
        6) What are Salesforce batch apex limitations?
        7) How to call batch apex class from apex trigger in Salesforce? 
        8) What is future method in Salesforce?
        9) What is Queueable apex in Salesforce?
      10) Explain chaining of Batch Jobs?
      11) Explain the error "Too many queueable jobs added to the queue"?
      12) Explain the error "Maximum stack depth has been reached"?
      13) Real time scenario for use of Batch Apex?
    

To further enhance your preparation, we've included a dedicated section with 30 interview questions, ensuring you're well-equipped to tackle any interview related to Batch Apex.

Get ready to embark on a learning journey that will sharpen your Batch Apex skills and open new doors of opportunity. Enroll now and let's delve into the world of Batch Apex together!

No comments:

Post a Comment