Monday, October 28, 2019

HOW TO DO CALLOUTS FROM APEX TRIGGER


In this blog post, we are going to see how we can do callouts from apex trigger.
As we know that trigger runs synchronously  we cannot make a callout to external system from trigger, this is because a trigger cannot wait for the execution to complete as this can cause performance issue, however an apex trigger can invoke a callout when the callout is made from a method which is defined as asynchronous.

Below is the sample structure to call Apex class method from trigger which makes callouts.

APEX TRIGGER:

trigger checkMeaningTrigger on checkMeaning__c (after insert) {
     if(avoidRecursionClass.booleanvar){
        avoidRecursionClass.booleanvar=false;     // Avoid recursion.
        populateMeaning.findMeaning(trigger.newmap.keyset()); // Passing ids of records.
     }
}

APEX CLASS:

public class populateMeaning {
    // Callout from trigger should be asynchronous
    @future(Callout=True)
    // Future method is always static
    // Getting the ids of the account
    public static void findMeaning(Set<id> IdSet){
        // CALLOUT CODE
    }
}   
 



SCENARIO: We are having the requirement that whenever a contact record is inserted in “Salesforce ORG1” we have to write a trigger on “After Insert” event on contact record which will call the apex class method and the method will do callout to other Salesforce org i.e (“Salesforce ORG2”) webservice. This webservice will insert the contact record in “Salesforce ORG2” with the information receives from “Salesforce ORG1”.

First of all, we have to create a connected app in “Salesforce ORG2” as shown in the below image. Also, create a remote site setting in “Salesforce ORG1” with URL of “Salesforce ORG2.



HOW TO DO CALLOUTS FROM APEX TRIGGER


REMOTE SITE Setting IN “Salesforce ORG1”.


how to call webservice from trigger in salesforce
Now the question is what is connected app?

For external application that needs to authenticate with Salesforce we need to create a connected app so as to inform Salesforce about the new authentication entry point. Connected app use standard OAuth 2.0 protocol to authenticate.

Note down the Consumer key, Consumer secret (We have to provide this information to “Salesforce ORG1”  for authentication purpose along with username, password, security token of user which “Salesforce ORG1”  will be using for authentication).

Now let’s create a trigger in “SALESFORCE ORG1” as shown below.

APEX TRIGGER:

trigger maintrigger on Contact (after insert) {
    Set<id> conIdSet=new Set<id>();
    for(Contact con:trigger.new){
        if(con.email!=Null){
            conIdSet.add(con.id);
        }
    }
    if(conIdSet.size() > 0){
        callWebserviceClass.getConList(conIdSet); // Calling apex class method
    }
}

Now let’s create a apex class “callWebserviceClass” in “SALESFORCE ORG1”.

APEX CLASS:

public class callWebserviceClass {
    private string cKey =’XXXXXXXXXXXXXXXXXXXXXX’;
    private string cSecret = ' XXXXXXXXXXXXXXXXXXXXXX ';
    private string uName = ‘XXXXXXXXXXXXXXXXXXXXXX’;
    private string passwd = ‘PASSWORD+SECURITYTOKEN’;
   
    public class responseWrapper {
        public string id;
        public string access_token;
        public string instance_url;
    }
    public string getRequestToken() {
        string reqBody = 'grant_type=password&client_id=' + cKey + '&client_secret=' + cSecret + '&username=' + uName + '&password=' + passwd;
        Http h = new Http();
        HttpRequest req = new HttpRequest();
        req.setBody(reqBody);
        req.setMethod('POST');
        req.setEndpoint('https://login.salesforce.com/services/oauth2/token');
        HttpResponse hresp = h.send(req);
        responseWrapper wResp = (responseWrapper) JSON.deserialize(hresp.getBody(), responseWrapper.class);
        system.debug('Instance url' + wResp.instance_url);
        system.debug('session id' + wResp.access_token);
        return wResp.access_token;
    }
    @future(callout = true)
    public static void getConList(Set < id > conIdSet) {
        String accToken;
        string responseBody;
        string endPoint = 'https://ap5.salesforce.com/services/apexrest/createContactRecord';
        callWebserviceClass obj = new callWebserviceClass();
        accToken = obj.getRequestToken();
        system.debug('access token' + accToken);
        if (accToken != '') {
            for (Contact con: [SELECT id, firstName, lastName, email from contact where id in: conIdSet]) {
                 system.debug('JSON' + JSON.serialize(con));
                Http h1 = new Http();
                HttpRequest req1 = new HttpRequest();
                req1.setHeader('Authorization', 'Bearer ' + accToken);
                req1.setHeader('Content-Type', 'application/json');
                req1.setMethod('POST');
                req1.setBody(JSON.serialize(con));
                req1.setEndpoint(endPoint);
                HttpResponse hresp1 = h1.send(req1);
                system.debug('hresp1' + hresp1);
            }
        }
    }
}

Now create a WEBSERVICE in “SALESFORCE ORG2” as  below.

@RestResource(urlMapping='/createContactRecord/*')
   global with sharing class createContactRecordCLass {
     @HttpPost
      global Static string fetchAccount(){
      RestRequest req = RestContext.request;
      RestResponse res = Restcontext.response;
      string jsonString=req.requestBody.tostring();
      responseWrapper wResp=(responseWrapper) JSON.deserialize(jsonString,responseWrapper.class);
      Contact obj=new Contact();
      obj.firstName=wResp.FirstName;
      obj.lastName=wResp.LastName;
      obj.email=wResp.email;
      Insert obj;
       
        return 'Success';
      }
      global class responseWrapper{
       global string FirstName;
       global string LastName;
       global string email;
      }
   }


Now let’s try to upload  a  .csv file containing 2 contact records in “SALESFORCE ORG1” as shown in the below image.

how to call webservice from trigger in salesforce

HOW TO DO CALLOUTS FROM APEX TRIGGER
Now let’s see the result from “SALESFORCE ORG2” we have two contacts created in ORG2 as well.


6 comments:

  1. Nice article, very well explained

    ReplyDelete
  2. thank you, but custom fields are not getting populated in destination org

    ReplyDelete
    Replies
    1. Hey I am facing the same issue. did you figure out how to do this?

      Delete
  3. This simple article has cleared lot of Concepts. Thanks

    ReplyDelete
  4. Very Nice Explained

    ReplyDelete