REST API Integration Salesforce apex

In this post we will see a working example for REST API integration. Generally when we use webservice or rest api we use it to integrate our salesforce instance with other systems. For a fresh salesforce developer having little or no knowledge about other programming languages like java, .net or other systems it becomes little difficult to get the real feel of integration specially if you haven't had the opportunity to work on real projects related to integration. Considering the dilemma of such fresh developers, i am writing this article which will demo REST api integration between two salesforce orgs. 


Rest api salesforce

In the example, we will be writing a apex class exposed as REST api in one org and in the second org we will consume that particular class. This will help us in learning both exposing and consuming REST API. Before we write the code let us see what pre-requisites are needed. 

First you will need two different salesforce developer orgs. Secondly, create a remote site setting with the url 'login.salesforce.com' in the source org. Let us write our REST api class that we want to expose in the target org.

@RestResource(urlMapping='/createNewAccountUsingRestAPI/*')
global with sharing class RESTCreateNewAccount{

    @HttpPost

    global static string createAccountRecord(String name) {
     string succError;
     account acc = new account();
     acc.name = name;      
     insert acc;
     acc.accountsource = 'Other';
     update acc;
     succError = 'New account has been created. Account Record id is:'+acc.id;
     return succError;
    }
 
    @httpput
    global static string updateAccountRecord(String name) {
       string returnmessage = 'Account are updated successfully';
       List<account> accupdateList = [select name,id,AccountSource from account where name =: name];
       for(account acc : accupdateList){
           acc.AccountSource = 'Web' ;
           returnmessage = returnmessage +acc.id;
       }
       try{
         update accupdateList;
       }
       catch(exception ex){
         returnmessage = ex.getmessage();
       }
       return returnmessage ;
    }          
}


Let us try to understand above class, specifically alien things(if you see closely theres only annotations that we need to understand rest of the things we use normally in our classes or controllers). Class has first line as @RestResource(urlMapping='/createNewAccountUsingRestAPI/*')

annotation '@RestResource' means you are exposing the class as REST api so that methods from this class can be called from outer systems. Secondly we have
--> urlMapping='/createNewAccountUsingRestAPI/*  this specifies the url that outer system needs to use to call that particular class.

Other annotations that we have used include @HttpPost and @HttpPut now this are being used against each method. @HttpPost is used to indicate that the method will have code to a dml that will create/insert new records on the other hand @HttpPut specifies that the code in that method will update the records (While writing the methods you have to make sure you follow these things other wise the code will give run time exception so make sure you only do update in @HttpPut method and so on). Apart from these method annotations we also have @Httpdelete and @HttpPatch annotations. Apart from annotations we also have to make sure the class is global for obvious reasons, class will be called by outside world.

In our @HttpPost method if you see closely we have written the code to do only a single and simple transactions of inserting one record which actually can be also be done by simply passing the information over a single url by outside system, but for sake for simplicity and understanding have used a REST exposed class in target org. Once we have the REST exposed class in target org its time to write a class in other org that would call above class. If you see the two methods above they create a new record and update an existing record, so when we will call 'post' method from our other org it will actually create the new account record in our target org.

Lets write a class in other org that will create a new account record in target org (by calling the exposed REST api class),

public class RestAPIcalloutExample{

   Public void loginToOtherOrgAndCreaetNewAccount(){

        /*Login to Other Salesforce Org to grab session id - begin*/
        HTTP h1 = new HTTP();
        HttpRequest request = new HttpRequest();      
        request.setEndpoint('https://login.salesforce.com/services/Soap/u/22.0');
        request.setMethod('POST');
        request.setHeader('Content-Type', 'text/xml;charset=UTF-8');
        request.setHeader('SOAPAction', '""');
        request.setBody('<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Header/><Body><login xmlns="urn:partner.soap.sforce.com"><username>' + 'myusername@cloudforece.com'+ '</username><password>' +'my_password1234'+ '</password></login></Body></Envelope>');
        String SERVER_URL;
        String SESSION_ID;
        HTTPResponse loginResponse = h1.send(request);     
        Dom.Document doc = loginResponse.getBodyDocument();
        Dom.XMLNode receivedXml= doc.getRootElement();
        SESSION_ID = receivedXml.getChildElement('Body', 'http://schemas.xmlsoap.org/soap/envelope/').getChildElement('loginResponse', 'urn:partner.soap.sforce.com').getChildElement('result','urn:partner.soap.sforce.com').getChildElement('sessionId','urn:partner.soap.sforce.com') .getText();      
        /*Login to Other salesforce Org to grab session id - finish*/
     
        /* Send https request to the custom REST API defined in other org that has urlmapping as 'createNewAccountUsingRestAPI' -begin*/
        HTTP h2 = new HTTP();
        HttpRequest request2CreateAccount = new HttpRequest();
        request2CreateAccount.setMethod('POST');
        request2CreateAccount.setHeader('Content-Type', 'application/json;charset=UTF-8');
        request2CreateAccount.setHeader('Accept', 'application/json');
        request2CreateAccount.setHeader('SOAPAction', '""');
        request2CreateAccount.setbody('{"name":"Cloudforce4u Technologies Ltd"}');
            request2CreateAccount.setEndpoint('https://ap1.salesforce.com/services/apexrest/createNewAccountUsingRestAPI');
        request2CreateAccount.setHeader('Authorization', 'OAuth '+SESSION_ID);             
        HTTPResponse resppnceFromOtherSFOrg = h2.send(request2CreateAccount);
        /* Send https request to the custom REST API defined in other org that hass urlmapping as updateaccountrec - finish*/
        system.debug('**-Output-**'+resppnceFromOtherSFOrg.getbody());
   }
 }


Before we decode each line of above class lets write point wise what we we need to do so as to call the target org exposed REST api class. It is obviously not the way (create instance of the class and then call that method)we call normal method from different classes within salesforce orgs.

1. Programatically login to the target org using login url, username and password
2. Once you are logged in try to get the session id
3. call the exposed class method using http callout

Now lets decode the whole code for each of the 3 steps separately.
1. Programatically  login to the target org using login url, username and password
You can login to salesforce org either by soap api or by REST api but since here we are discussing REST lets use REST to login and 

Subsequently get the session id. So basically in REST we will have to create a instance of http, httpresponse and then send the request over http. Now to send this http request what all things need to set? below are the details
a. End point url (this will the login url)
b. Kind of method you want to call POST,PUT etc (we have set it to POST that means we we will be calling our post method from target org)
c. Header like body content type, it could be json or xml in our case we are using xml.
d. set body of the request which will have username,password

Once our request is ready we need to send it over http and store the response in httpresponse variable.

2. Once you are logged in try to get the session id
Once we get response in httpresponse variable its time to segregate the response and get the real thing out of it. The response will have many things but we should take out the exact thing/data that we need, in this case it is the session id. When we sent the login request in step 1 it logged in and whenever you log in to slaesforce it automatically creates a session id, this session id will be needed while sending the actual request to call the POST method in target org. Now, how do we get the session id from response? To do that we need to parse the response xml. This is done by getting the body element and getting the root elements (you can go through articles which give insights above parsing xml). Once we have the session id we are ready to call the exposed REST class from target org through http callout.

3.  Call the exposed class method using http callout
This will be similar to step 2 except few changes. End point url in this case is as below
 request2CreateAccount.setEndpoint('https://ap1.salesforce.com/services/apexrest/createNewAccountUsingRestAPI');
This url specifies that we are calling REST api exposed class  (https://ap1.salesforce.com/services/apexrest) and then specifies the class name.
Now the question is how does it which method to call? It will call post method 'createAccountRecord' because we have set setmethod as 'POST'         
request2CreateAccount.setMethod('POST'); 
to call put method just change POST to PUT         
request2CreateAccount.setMethod('PUT')

Next thing that we have set is authorisation -        
request2CreateAccount.setHeader('Authorization', 'OAuth '+SESSION_ID);
This where we need session id and this was the reason we used first http callout to login into salesforce org. We also need to set the body of the request, in this case have set to json. Make sure you are sending the target org method parameter in the body. 

Once you have both the classes saved and remote site setting created in target org just execute the method in other org using developer console.

RestAPIcalloutExample restcall = new RestAPIcalloutExample(); 
restcall.loginToOtherOrgAndCreaetNewAccount();

New account record would be created in target org, you can see the id of the record using debug log.
 system.debug('**-Output-**'+resppnceFromOtherSFOrg.getbody());

6 comments:

  1. Thanks Yoganand Gadekar .It helped me a lot in understanding.

    ReplyDelete
  2. hey i am getting null pointer exception @line no 17...

    RestAPIcalloutExample class

    ReplyDelete
    Replies
    1. Use security token along with your password.

      Delete
  3. hey i am getting null pointer exception @line no 17... i am also getting the same error

    ReplyDelete
  4. Hi,

    The reason for getting null pointer exception @line 17 is... If user not able to login into salesforce. Please check credentials provided @line 11.

    Regards,
    Srinath T.

    ReplyDelete
  5. Hi, Currently there is one method 'createAccountRecord' only under @HttpPost, so when 'SetMethod' is 'POST' it'd be invoked...what if more than one method under @HttpPost, which method will be invoked...is there any way to specifically call the method?

    Thanks,
    Muthu

    ReplyDelete