
Salesforce to Salesforce Integration using Rest API Callouts
"Integration" itself is a vast topic, though with a bit of understanding and practise one can master any skill whatsoever. Answering the question posted hereĀ is what I think is the best solution for Salesforce to Salesforce Integration using Rest API Callouts:
Donāt forget to check out: Apex Web Services and callouts
For the reason of integrating two Salesforce Orgs which in our case, between two separate Salesforce Orgs, we have to assume one Org as Client or SourceĀ and another as Server or Destination or Target, so here whenever an Account record is created in the Source Org, data automatically will be pushed in Account object at Destination Org.
Let's start our journey now.
Prerequisites:
- Source org endpoint: https://akashmishra-dev-ed.my.salesforce.com/ (Donāt get confused as this is the custom URL I used, you can use the Instance URL for your org like https://ap5.salesforce.com).
- Destination Org URL: https://ap4.salesforce.com
First, we talk about what we have to do in the Destination org:
Step 1.
Create a Connected App in Destination org giving the callback URL with the details as mentioned in the image below.
Now donāt forget to copy the Consumer Key (Client id) and Consumer Secret (Client Secret) weāll need these in Source org Rest Callout Class.
Step 2.
Create a Rest Webservice with @httpPost & @httpGet verb, though itās not required in ourĀ case.
Find the class below.
/********************************************************************* * Description ā Apex REST service with GET and POST methods * Author ā AP Json format { ānameā : āAkashā, āphoneā : ā8826031286ā, āwebsiteā : āwww.akashmishra.co.inā } ***********************************************************************/ @RestResource(urlMapping=ā/v3/accounts/*ā) global with sharing class REST_AccountService_V4 { @HttpPost global static AccountWrapper doPost(String name, String phone, String website) { RestRequest req = RestContext.request; RestResponse res = RestContext.response; AccountWrapper response = new AccountWrapper(); Account acct = new Account(); acct.Name = name; acct.Phone = phone; acct.Website = website; insert acct; response.acctList.add(acct); response.status = āSuccessā; response.message = āYour Account was created successfully.ā; return response; } @HttpGet global static AccountWrapper doGet() { RestRequest req = RestContext.request; RestResponse res = RestContext.response; AccountWrapper response = new AccountWrapper(); String accountId = req.requestURI.substring(req.requestURI.lastIndexOf(ā/ā)+1); if(doSearch(accountId)){ searchAccounts(req, res, response); } else{ findAccount(res, response, accountId); } return response; } // If the item to the right of the last forward slash is āaccountsā, the request went to //v3/accounts?Name=Akash // Else the request went to v3/accounts/<something>, which is not a search, but a specific //entity private static boolean doSearch(String accountId) { if(accountId == āaccountsā) { return true; } return false; } //If the request came to /v3/accounts, then we want to execute a search Public static void searchAccounts(RestRequest req, RestResponse res, AccountWrapper response) { //Use the RestRequestās params to fetch the Name parameter String searchTerm = req.params.get(āNameā); if(searchTerm == null || searchTerm == ā) { response.status = āErrorā; response.message = āYou must provide a Name for your search term.ā; res.StatusCode = 400; } else { String searchText = ā%ā+searchTerm+ā%ā; List<Account> searchResults = [SELECT Id, Name, Phone, Website FROM Account WHERE Name LIKE : searchText]; if(searchResults != null && searchResults.size() > 0) { response.acctList = searchResults; response.status = āSuccessā; response.message = searchResults.size() + ā Accounts were found that matched your search term.ā; } else { response.status = āErrorā; response.message = āNo Accounts were found based on that Name, please search again.ā; } } } //If the request came to v3/accounts/sometext then we want //to find a specific account Public static void findAccount(RestResponse res, AccountWrapper response, String accountId) { // Provided we recevied an External Id, perform the search and return the results if(accountId != null && accountId != ā) { List<Account> result = [SELECT Id, Name, Phone, Website FROM Account WHERE External_Id__c =: accountId]; if(result != null && result.size() > 0) { response.acctList.add(result[0]); response.status = āSuccessā; } else { response.status = āErrorā; response.message = āThis account could not be found, please try again.ā; res.StatusCode = 404; } } // If the request came to /v3/accounts/ (without an Account Id), //return an error else { response.status = āErrorā; response.message = āYou must specify an External Id.ā; res.StatusCode = 400; } } global class AccountWrapper { public List<Account> acctList; public String status; public String message; public AccountWrapper(){ acctList = new List<Account>(); } } }
Note: Please ignore the Naming conventions as they may look funny.
Now is the timeĀ to configure the Source org:
Step 1.
Create Remote site in Source like in my case I created the below one.
Step 2.
Create a class for Rest Callout in the Source org. Goto: Create==>Apex Class==>Click New /******************************************************************* *Description: Rest Callout *Owner: AP ********************************************************************/ public class SendAccount { //Use your Client Id String clientId =3MVG9YDQS5WtC11o4mAP_I****************************** OoLrKY3FUrb6221Ms9hjkqhZo_oTNbjKu2LJBHN_tFmZ1.ā; //Use your Client Secret String clientsecret=ā314426******97831ā²; //Your Destination org username String username=ā[email protected]ā; //Your Destination orgPassword+Security Token String password=ā[email protected]ā; String accesstoken_url=āhttps://login.salesforce.com/services/oauth2/tokenā; String authurl=āhttps://login.salesforce.com/services/oauth2/authorizeā; public class deserializeResponse { public String id; public String access_token; } public String ReturnAccessToken(SendAccount Acc){ String reqbody = āgrant_type=password&client_id=ā+clientId+ā&client_secret=ā +clientSecret+ā&username=ā+username+ā&password=ā+password; // String reqbody='{āgrant_typeā:āpasswordā,āclient_idā:clientId,āclient_secretā:clientSecret, āusernameā:username,āpasswordā:password}ā; Http h= new Http(); HttpRequest req= new HttpRequest(); req.setBody(reqbody); req.setMethod(āPOSTā); //Change āap4ā in url to your Destination Org Instance req.setEndpoint(āhttps://ap4.salesforce.com/services/oauth2/tokenā); HttpResponse res=h.send(req); System.debug(res.getBody()+āBy-AP-1986-Responseā); deserializeResponse resp1= (deserializeResponse)JSON.deserialize(res.getBody(),deserializeResponse.class); System.debug(resp1+āBy-AP-deserializeresponseā); return resp1.access_token; } @future(callout=true) public static void createAccount(String Accname, String Phone, String Website){ SendAccount acc1= new SendAccount(); String accessToken=acc1.ReturnAccessToken(acc1); System.debug(accessToken+ā###APā); if(accessToken!=null){ //Change āap4ā in url to your Destination Org String endPoint=āhttps://ap4.salesforce.com/services/data/v32.0/sobjects/Accountā; String jsonstr='{āNameā:āā+ Accname +'ā,āPhoneā:āā+ Phone +'ā,āWebsiteā:āā+ Website +'ā}ā; Http h2= new Http(); HttpRequest req2= new HttpRequest(); req2.setHeader(āAuthorizationā,āBearer ā + accessToken); req2.setHeader(āContent-Typeā,āapplication/jsonā); req2.setHeader(āacceptā,āapplication/jsonā); req2.setBody(jsonstr); req2.setMethod(āPOSTā); req2.setEndpoint(endPoint); HttpResponse res2=h2.send(req2); System.debug(res2+ā###Akash###ā); deserializeResponse deresp= (deserializeResponse)System.JSON.deserialize(res2.getBody(),deserializeResponse.class); System.debug(ā### Deserialized Response ###ā+deresp); } } }
Now Create a Trigger to make callout when some data is inserted in the Account Object.
Try This:
Trigger SendMyAccount on Account (after insert) {for(Account a:Trigger.new) {SendAccount.createAccount(a.name, a.Phone, a.Website); } }
Now save and start testing by creating a record on Account Object in Source Org. I hope you got it right.
Thanks, everyone,
"Don't let the tiny bit of Doubt today be a road-blocker Tomorrow", so keep on asking friends.
"Happy Learning"
In the Org, which we do the callout (Ap4)...
The end point you set isĀ 'https://ap4.salesforce.com/services/data/v32.0/sobjects/Account';
if you are making callout to the Org in which you defined the webservices...
But, Ā the last part should be Ā "services/apexrest/v3/accounts/" right??
Nice Blog Akash. It is really helpful to understand the concept of REST Integration.
Thank you for your efforts.
Amit
Hi Akash.Ā Will you provide test(s)?Ā I can't 100% cover the REST callout.Ā Thanks!