Wednesday, November 25, 2015

How to do Integration between two different organizations in salesforce Using REST API and REST Web Service and Apex Web Service?

For this post, I will offer a simple explanation of the complex, yet interesting areas essential for the complete understanding of Salesforce Integration’s capabilities. The business scenario quoted, along with the working code samples, will be a good starting point for entering into the world of non-declarative ways for integrating with Salesforce. Here’s what I’ll cover:

Understanding authentication and its prerequisites
OAuth authentication flows for REST API calls
Apex triggers and callouts
REST API, REST web services, and Apex web services

1) Authentication and Its Prerequisites
Authenticating a client application is the first and foremost step while building an interface.

The authentication method depends on your chosen call type (REST or SOAP). Let’s see how to do it using REST.

Before moving any further, let’s frame a business scenario. We’ll use two Salesforce instances that exchange Account details. When a new Account is created in one org, it will flow down to the other Salesforce org, and in return the source org will get the Salesforce Record ID of the created record. These two orgs are:

Source Salesforce org (used for callout) – Source
Target Salesforce org (used for receiving requests) – Target

Following our business scenario, we can say that authentication is a collection of the following sub-steps. Though actual authentication calls a trigger from the Apex code, consider these steps as the prerequisites because without them being completed first, the authentication calls won’t work.

Choosing OAuth Endpoint (to be invoked from Source org)
Choosing OAuth Authentication flow (to be used by Source org)

Remote Site Setting in Source Org.




Connected App enables Salesforce to recognize and authenticate an external application as a new entry point. OAuth is used for this authentication. We need to create a Connected App record in Target org. Below is an illustration.

Connected App in Target Org.




callback url should be specified in the remote site setting
Once after saving the record the client id and clientSecret are generated.

Create a Trigger to make an asynchronous call from source org to target org

Trigger on account Object:


trigger SendAccount on Account(after insert)
{
for(Account a : Trigger.new){
SendAccountFromSource.createAccount(a.Name, a.Id);
}
}

Apex Class to make a callout :

Replace the clientid,secret,username and password's of your org.
public class SendAccountFromSource {
private final String clientId = 'Clent Id from App';
private final String clientSecret = 'clientSecretfrom app';
private final String username = 'username';
private final String password = 'passwordwithsecuritytoken';
public class deserializeResponse
{
public String id;
public String access_token;
}
public String ReturnAccessToken (SendAccountFromSource acount)
{
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');
req.setEndpoint('https://ap2.salesforce.com/services/oauth2/token');
HttpResponse res = h.send(req);
deserializeResponse resp1 = (deserializeResponse)JSON.deserialize(res.getbody(),deserializeResponse.class);
return resp1.access_token;
}
@future(callout=true)
public static void createAccount(String accName, String accId) 
{
SendAccountFromSource acount = new SendAccountFromSource();
String accessToken = acount.ReturnAccessToken (acount);

if(accessToken != null)
{
String endPoint = 'https://ap2.salesforce.com/services/data/v32.0/sobjects/Account/';
String jsonstr = '{"Name" : "' + accName + '"}';
Http h2 = new Http();
HttpRequest req1 = new HttpRequest();
req1.setHeader('Authorization','Bearer ' + accessToken);
req1.setHeader('Content-Type','application/json');
req1.setHeader('accept','application/json');
req1.setBody(jsonstr);
req1.setMethod('POST');
req1.setEndpoint(endPoint);
HttpResponse res1 = h2.send(req1);

deserializeResponse resp2 = (deserializeResponse)JSON.deserialize(res1.getbody(),deserializeResponse.class);
Account a = [SELECT Id FROM Account WHERE Id = :accId];
a.externalId__c = resp2.id;
update a;
}
}
}
Explanation –
1 Setting the REST API resource to create an Account (sObject)
2 Creating the JSON string to be sent as the input
3 Setting the Header to include the access token
4 Querying the Account record in Source Org so it can be updated
5 Setting the custom foreign key field on Account in Source Org with the extracted Account ID from the response.

Till here we have worked with Rest API.

REST Webservices

When working with rest webservices we need to change the code in the createAccount method in SendAccountFromSource class . Which looks like
if(accessToken != null)
{
String endPoint = 'https://ap2.salesforce.com/services/apexrest/v1/createAccount/';
String jsonstr = '{"AccName" : "' + accName + '"}';

Http h2 = new Http();
HttpRequest req1 = new HttpRequest();
req1.setHeader('Authorization','Bearer ' + accessToken);
req1.setHeader('Content-Type','application/json');
req1.setHeader('accept','application/json');
req1.setBody(jsonstr);
req1.setMethod('POST');
req1.setEndpoint(endPoint);
HttpResponse res1 = h2.send(req1);

String trimmedResponse = res1.getBody().unescapeCsv().remove('\\');
deserializeResponse resp2 = (deserializeResponse)JSON.deserialize(trimmedResponse, deserializeResponse.class);
Account a = [SELECT Id FROM Account WHERE Id = :accId];
a.externalId__c= resp2.id;
update a;
}

Here in this example we need to change the endpoint url that is pointing to createAccount class in the target org. Create a new rest web service class createAccount in target org.

@RestResource(urlMapping='/v1/createAccount/*')
global with sharing class createAccount 
{
@HttpPost
global static String createAccount(String AccName)
{
Account a = new Account();
a.Name = AccName;
insert a;
String returnResponse = JSON.serialize(a);
return returnResponse;
}
}
Explanation –
1 Exposing the web service using the @RestResource annotation
2 Exposing method as REST resource to be called when HTTP Post request is made to this web service
3 Creating a new Account in Target org and setting the name as passed from Source org
4 Serializing the response (Account details) before sending
5 Sending the response.

Apex Web Service

Finally, the third option is the Apex Web Service that uses SOAP to handle integration. The class written at the target needs to be exposed as a global Web Service.

global class CreateAccountApexWS 
{
global class sAccount
{
webservice String name;
}
webservice static String createAccount(sAccount sAcct)
{
Account acct = new Account();
acct.Name = sAcct.name;
insert acct;
String returnResponse = JSON.serialize(acct);
return returnResponse;
}
}
Explanation –
1 Creating a Global class that can be accessed from anywhere
2 Using the webservice keyword to expose class variable as an input to the web service
3 Using the webservice keyword to expose the class method as a custom SOAP Web Service

7 comments:

  1. Thank you for giving us great info on integration of salesforce.

    Salesforce Integration Services

    ReplyDelete
  2. Very interesting information of salesforce Integration. I have read your blog. This is informative for us. Salesforce Integration Services.

    ReplyDelete
  3. I acknowledge the author for his brilliant work for making this exceptionally useful and informative content to guide us.
    Form Builder with Salesforce Integration

    ReplyDelete
  4. Great Explanation, Thank You author !!!

    ReplyDelete
  5. I really enjoyed while reading your article and it is good to know the latest updates. Do post more. Please also read my topics about

    Salesforce Products
    Salesforce Consultant
    Salesforce Integration Service

    ReplyDelete