HTTP Callout from Triggers to external web services in Salesforce

Concept

Let’s consider a scenario, we want to callout to an external service to post or get some data when we create or update a record and we do want to show a toast message response based on that callout.

Now, as we are aware callouts cannot be made from triggers synchronously as that would hold up the database transaction until the callout is completed. Considering the governor limits in place we can have up to 120 seconds. This in turn could cause significant contention with other transactions and might impact performance.

The only way that you can execute a http callout from a trigger is to run asynchronously. For example by executing a method with the @future method in a separate thread so as to not stall the transaction awaiting a response from the callout.

HTTP Callout Example to external web services

Taking an instance of a lead record that needs to update a geotag via a webservice. We can start as below.

Have a trigger to run the context we require. We must keep the trigger logic less, but have put it here for the sake of not having three classes here.

trigger triggerLead on Lead (after insert, after update) {
    if(System.isFuture()) {
        return; // This is a recursive update, let's skip
    }
    Set<Id> updateLead = new Set<Id>();
    for(Integer i = 0, s = Trigger.new.size(); i < s; i++) {
        Lead oldRecord = Trigger.isInsert? null: Trigger.old[i], newRec = Trigger.new[i];
        if((Trigger.isInsert && newRec.geoTag__c != null) ||
        (Trigger.isUpdate && newRec.geoTag__c != null && 
            (newRec.Region_Code__c == null || newRec.geoTag__c != oldRecord.geoTag__c))) {
            updateLead.add(newRec.Id);
            if(updateLead.size() == 100) { // Max callout limit 100
                GetGeoTag.fetchGeoTag(updateLead);
                updateLead.clear();
            }
        }
    }
    if(updateLead.size() > 0) {
        GetGeoTag.fetchGeoTag(updateLead);
    }
}

We can use a future call to then make a callout and update the record on that field.

public with sharing class GetGeoTag {
    @future (callout=true)
    static public void fetchGeoTag(Set<Id> leadIDs){
        Lead[] records = [Select id, geoTag__c from Lead where id = :leadIds];
        for(Lead record: records) {
            HttpRequest req = new HttpRequest();
            req.setEndpoint('https://api.geotag.com/'+record.geoTag__c+'?access_key=e767bdd2ee983a9407fccd6ccb7bff0e'); 
            req.setMethod('GET');
            HttpResponse res = new http().send(req);
            Map<string,object> m = (Map<string,object>)JSON.deserializeUntyped(res.getbody());
            String regioncode=(String)m.get('region_code');
            String regionname=(String)m.get('region_name');
            String countrycode=(String)m.get('country_code');
            String countryname=(String)m.get('country_name');
            record.Region_Code__c = regioncode;
        }
        update records;
    }
}

If you are trying to return a response to the user, create a process builder which runs when record is update. Using that we can show a toast message. What else can we do ? Have opinions on that ? Feel free to drop comment

Read More: Salesforce Integration Interview Questions

Leave a Reply

error: Content is protected !!