Showing posts with label SoapUI. Show all posts
Showing posts with label SoapUI. Show all posts

12 April 2015

Using SoapUI to do SOAP calls to Salesforce

I've been involved on integration with Salesforce.com from and to other systems. One of the oldest protocol used on integrating with the system is using the SOAP protocol as it has a SOAP API that allows other systems to manipulate records. 

Personally, its worth while to have knowledge on how to consume the Salesforce SOAP method specially if you are working with an integrator who does not have prior experience integrating to Salesforce using the protocol. 

In the below examples I will be using SoapUI, an open source testing tool that supports not just SOAP but also other protocols such as REST and HTTP. I'll also be using the Salesforce partner wsdl but will provide alternative examples using the enterprise wsdl. For more information on the difference of the two, please take time to read this article.

The first thing to do is to download the Salesforce WSDL from Setup --> Develop --> API.


Once the WSDL is generated and download, we need to create a new SOAP project in SoapUI as depicted below.


Clicking the "Ok" will create the project as well as list the SOAP methods and samples (if "Create Request" checkbox is selected). Below is the generated project tree.


So let's starting creating our sample SOAP calls.

Partner login call

There are different ways of authenticating with Salesforce but for our example, we will use the login method that require to pass the user name and password to get a Session ID which is an encrypted value Salesforce pass back which is needed for succeeding calls.

Go to the login method from the SoapUI project tree and use or create a new request. Delete all of the values under <soapenv:Header> as we don't need to pass any value on the SOAP envelop. We will refer to this as the soap envelop header moving forward.

The request should be as follow (click here for the enterprise wsdl sample):


<soapenv:Envelope 
     xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"     
     xmlns:urn="urn:partner.soap.sforce.com">
   <soapenv:Header>
   </soapenv:Header>
   <soapenv:Body>
      <urn:login>
         <urn:username>Salesforce User Name</urn:username>
         <urn:password>Password + security token</urn:password>
      </urn:login>
   </soapenv:Body>
</soapenv:Envelope>

From the request window, click the submit  icon to process the request. SoapUI will then attempt to do a SOAP call to Salesforce and returns a response below.


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="urn:partner.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Body>
      <loginResponse>
         <result>
            <metadataServerUrl>
              https://na5.salesforce.com/services/Soap/m/30.0/00D700000008fqn
            </metadataServerUrl>
            <passwordExpired>false</passwordExpired>
            <sandbox>false</sandbox>
            <serverUrl>
              https://na5.salesforce.com/services/Soap/u/30.0/00D700000008fqn
            </serverUrl>
            <sessionId>Session ID</sessionId>
            <userId>005700000012RyAAAU</userId>
            <userInfo>
               <accessibilityMode>false</accessibilityMode>
               <currencySymbol>$</currencySymbol>
               <orgAttachmentFileSizeLimit>5242880</orgAttachmentFileSizeLimit>
               <orgDefaultCurrencyIsoCode>USD</orgDefaultCurrencyIsoCode>
               <orgDisallowHtmlAttachments>false</orgDisallowHtmlAttachments>
               <orgHasPersonAccounts>true</orgHasPersonAccounts>
               <organizationId>00D700000008fqnEAA</organizationId>
               <organizationMultiCurrency>false</organizationMultiCurrency>
               <organizationName>REMOVED</organizationName>
               <profileId>00e70000000sEkZAAU</profileId>
               <roleId>00E70000000olJBEAY</roleId>
               <sessionSecondsValid>7200</sessionSecondsValid>
               <userDefaultCurrencyIsoCode xsi:nil="true"/>
               <userEmail>REMOVED</userEmail>
               <userFullName>REMOVED</userFullName>
               <userId>005700000012RyAAAU</userId>
               <userLanguage>en_US</userLanguage>
               <userLocale>en_US</userLocale>
               <userName>REMOVED</userName>
               <userTimeZone>America/Los_Angeles</userTimeZone>
               <userType>Standard</userType>
               <userUiSkin>Theme3</userUiSkin>
            </userInfo>
         </result>
      </loginResponse>
   </soapenv:Body>
</soapenv:Envelope>

Note that I have removed a couple of information from the response. However, the most important thing to note from the response is the Session ID and the ServerURL which we will used in our succeeding examples.

Our SoapUI should look like below:


Partner create call

Now that we have a Session ID and Server URL, we need to create a new request using the create method. Go to the create method from our project tree and use or create a new request. Delete all of the values soap envelop header except for <urn:SessionHeader> where we will need to add the Session ID value from the login call.

The request should be as follow (click here to see create call using enterprise wsdl):


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:urn="urn:partner.soap.sforce.com" 
    xmlns:urn1="urn:sobject.partner.soap.sforce.com">
   <soapenv:Header>
      <urn:SessionHeader>
         <urn:sessionId>Session ID from Login Call</urn:sessionId>
      </urn:SessionHeader>
   </soapenv:Header>
   <soapenv:Body>
      <urn:create >
         <urn:sObjects>
            <urn1:type>Account</urn1:type>
            <Name>Sample Account (Partner)</Name>
         </urn:sObjects>
      </urn:create>
   </soapenv:Body>
</soapenv:Envelope>

Note that we have manually typed the type node (represents the SObject type) and Name (which is the API name of the standard Name field) above for the request.

Before submitting the request, we also need to change the submit endpoint using the Server URL login response.



Below is the response from the create call.


<soapenv:Envelope 
     xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"    
     xmlns="urn:partner.soap.sforce.com">
   <soapenv:Header>
      <LimitInfoHeader>
         <limitInfo>
            <current>2</current>
            <limit>15000</limit>
            <type>API REQUESTS</type>
         </limitInfo>
      </LimitInfoHeader>
   </soapenv:Header>
   <soapenv:Body>
      <createResponse>
         <result>
            <id>0017000001ExlcFAAR</id>
            <success>true</success>
         </result>
      </createResponse>
   </soapenv:Body>
</soapenv:Envelope>

Note that the <createResponse> node will have the result of the call. The <id> will contain the record Id for the record you are creating and the <success> will tell whether the call is successful or not.

The SoapUI should look like below:



Partner update call

Using the same Session ID, Server URL and the record Id from the create call, use or create a new update request from the SoapUI project tree and delete all the values from the soap envelop header except for the SessionHeader. The request should look as below (click here to see update call using enterprise WSDL):


<soapenv:Envelope 
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:urn="urn:partner.soap.sforce.com" 
    xmlns:urn1="urn:sobject.partner.soap.sforce.com">
   <soapenv:Header>
      <urn:SessionHeader>
         <urn:sessionId>Session ID from Login Call</urn:sessionId>
      </urn:SessionHeader>
   </soapenv:Header>
   <soapenv:Body>
      <urn:update>
         <!--Zero or more repetitions:-->
         <urn:sObjects>
            <urn1:type>Account</urn1:type>
            <Name>Sample Account (Partner) Updated</Name>
            <urn1:Id>0017000001ExlcFAAR</urn1:Id>
         </urn:sObjects>
      </urn:update>
   </soapenv:Body>
</soapenv:Envelope>


The response is below:


<soapenv:Envelope 
     xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"    
     xmlns="urn:partner.soap.sforce.com">
   <soapenv:Header>
      <LimitInfoHeader>
         <limitInfo>
            <current>3</current>
            <limit>15000</limit>
            <type>API REQUESTS</type>
         </limitInfo>
      </LimitInfoHeader>
   </soapenv:Header>
   <soapenv:Body>
      <updateResponse>
         <result>
            <id>0017000001ExlcFAAR</id>
            <success>true</success>
         </result>
      </updateResponse>
   </soapenv:Body>
</soapenv:Envelope>

The SoapUI should look like below:





Partner upsert call

The upsert call is not much different with the update call except that there is an <externalIDFieldName> node that is required to have the API name of the field marked as external Id or the Id field. The field must be part of the request.

Below is the sample request using the same Session ID , Server URL and record Id which was used as the external id fr(click here to see update call using enterprise wsdl):


<soapenv:Envelope 
     xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"  
     xmlns:urn="urn:partner.soap.sforce.com" 
     xmlns:urn1="urn:sobject.partner.soap.sforce.com">
   <soapenv:Header>
      <urn:SessionHeader>
         <urn:sessionId>0Session ID from Login Call</urn:sessionId>
      </urn:SessionHeader>
   </soapenv:Header>
   <soapenv:Body>
      <urn:upsert>
         <urn:externalIDFieldName>Id</urn:externalIDFieldName>
         <!--Zero or more repetitions:-->
         <urn:sObjects>
            <urn1:type>Account</urn1:type>
            <!--Zero or more repetitions:-->
            <Name>Sample Account (Partner) Upserted</Name>
            <Id>0017000001ExlcFAAR</Id>
         </urn:sObjects>
      </urn:upsert>
   </soapenv:Body>
</soapenv:Envelope>

Below is the response.

<soapenv:Envelope 
     xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
     xmlns="urn:partner.soap.sforce.com">
   <soapenv:Header>
      <LimitInfoHeader>
         <limitInfo>
            <current>4</current>
            <limit>15000</limit>
            <type>API REQUESTS</type>
         </limitInfo>
      </LimitInfoHeader>
   </soapenv:Header>
   <soapenv:Body>
      <upsertResponse>
         <result>
            <created>false</created>
            <id>0017000001ExlcFAAR</id>
            <success>true</success>
         </result>
      </upsertResponse>
   </soapenv:Body>
</soapenv:Envelope>

Here is the SoapUI screenshot:



Most of the other SOAP methods follow the same request sample. However there are other functionalities such as running assignment rules, changing the debug log levels that are controlled via the envelop header.

Hopefully the example above can help anyone starting to learn integrating to Salesforce.com. :-)

Sample Salesforce SFDC Enterprise upsert

This is a sample SOAP Upsert using Enterprise WSDL. Note that we only passing the session Id  on the header information since we don't need the others and that the envelop must be posted to the ServerURL you got from the login call as per described in this blogpost. In addition, we need to put a value on the <externalIDFieldName> node with the field API name of the objects external Id. In this example, I used the Salesforce standard Id field.


<soapenv:Envelope 
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:urn="urn:enterprise.soap.sforce.com" 
    xmlns:urn1="urn:sobject.enterprise.soap.sforce.com"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Header>
      <urn:SessionHeader>
         <urn:sessionId>Session ID from login call</urn:sessionId>
      </urn:SessionHeader>
   </soapenv:Header>
   <soapenv:Body>
      <urn:upsert>
         <urn:externalIDFieldName>Id</urn:externalIDFieldName>
         <urn:sObjects xsi:type="Account">
            <Id>0017000001ExVRDAA3</Id>
            <Name>Sample Account (Enterprise) Upserted</Name>
         </urn:sObjects>
      </urn:upsert>
   </soapenv:Body>
</soapenv:Envelope>

Below is the sample SOAP response:

<soapenv:Envelope 
     xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
     xmlns="urn:enterprise.soap.sforce.com">
   <soapenv:Header>
      <LimitInfoHeader>
         <limitInfo>
            <current>11</current>
            <limit>15000</limit>
            <type>API REQUESTS</type>
         </limitInfo>
      </LimitInfoHeader>
   </soapenv:Header>
   <soapenv:Body>
      <upsertResponse>
         <result>
            <created>false</created>
            <id>0017000001ExVRDAA3</id>
            <success>true</success>
         </result>
      </upsertResponse>
   </soapenv:Body>
</soapenv:Envelope>

NOTE:

The <createResponse> node will have the result of the call. The <id> will contain the record Id in SFDC for the record you are creating and the <success> will tell whether the call is successful or not.

*I noticed that SoapUI 5.0.0 does not automatically add the xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance". This is important when you are setting the object type <urn:sObjects> tag.

Sample Salesforce Enterprise SOAP update

This is a sample SOAP Update using Enterprise WSDL. Note that we only passing the session Id  on the header information since we don't need the others and that the envelop must be posted to the ServerURL you got from the login call as per described in this blogpost.


<soapenv:Envelope 
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:urn="urn:enterprise.soap.sforce.com" 
    xmlns:urn1="urn:sobject.enterprise.soap.sforce.com"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Header>
      <urn:SessionHeader>
         <urn:sessionId>Session ID from login call</urn:sessionId>
      </urn:SessionHeader>
   </soapenv:Header>
   <soapenv:Body>
      <urn:update>
         <urn:sObjects xsi:type="Account">
            <Id>0017000001ExVRDAA3</Id>
            <Name>Sample Account (Enterprise) Updated</Name>
         </urn:sObjects>
      </urn:update>
   </soapenv:Body>
</soapenv:Envelope>

Below is the sample SOAP response:


<soapenv:Envelope 
     xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"      
     xmlns="urn:enterprise.soap.sforce.com">
   <soapenv:Header>
      <LimitInfoHeader>
         <limitInfo>
            <current>10</current>
            <limit>15000</limit>
            <type>API REQUESTS</type>
         </limitInfo>
      </LimitInfoHeader>
   </soapenv:Header>
   <soapenv:Body>
      <updateResponse>
         <result>
            <id>0017000001ExVRDAA3</id>
            <success>true</success>
         </result>
      </updateResponse>
   </soapenv:Body>
</soapenv:Envelope>

NOTE:

The <createResponse> node will have the result of the call. The <id> will contain the record Id in SFDC for the record you are creating and the <success> will tell whether the call is successful or not.

*I noticed that SoapUI 5.0.0 does not automatically add the xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance". This is important when you are setting the object type <urn:sObjects> tag.

Sample Salesforce Enterprise SOAP create

This is a sample SOAP Create using Enterprise WSDL. Note that we only passing the session Id  on the header information since we don't need the others and that the envelop must be posted to the ServerURL you got from the login call as per described in this blogpost.


<soapenv:Envelope 
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:urn="urn:enterprise.soap.sforce.com" 
    xmlns:urn1="urn:sobject.enterprise.soap.sforce.com"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Header>
      <urn:SessionHeader>
         <urn:sessionId>Session ID from login call</urn:sessionId>
      </urn:SessionHeader>
   </soapenv:Header>
   <soapenv:Body>
      <urn:create>
         <urn:sObjects xsi:type="Account">
            <Name>Sample Account (Enterprise)</Name>
         </urn:sObjects>
      </urn:create>
   </soapenv:Body>
</soapenv:Envelope>

Below is the sample SOAP response:


<soapenv:Envelope 
     xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"    
     xmlns="urn:enterprise.soap.sforce.com">
   <soapenv:Header>
      <LimitInfoHeader>
         <limitInfo>
            <current>9</current>
            <limit>15000</limit>
            <type>API REQUESTS</type>
         </limitInfo>
      </LimitInfoHeader>
   </soapenv:Header>
   <soapenv:Body>
      <createResponse>
         <result>
            <id>0017000001ExVRDAA3</id>
            <success>true</success>
         </result>
      </createResponse>
   </soapenv:Body>
</soapenv:Envelope>

NOTE:

The <createResponse> node will have the result of the call. The <id> will contain the record Id in SFDC for the record you are creating and the <success> will tell whether the call is successful or not.

*I noticed that SoapUI 5.0.0 does not automatically add the xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance". This is important when you are setting the object type <urn:sObjects> tag.

Sample Salesforce Enterprise SOAP login

This is a sample SOAP Login using Enterprise WSDL. Note that we are not passing any header information here for the sake of example.


<soapenv:Envelope 
        xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:urn="urn:enterprise.soap.sforce.com">
   <soapenv:Header>
   </soapenv:Header>
   <soapenv:Body>
      <urn:login>
         <urn:username>replace this with our SFDC username</urn:username>
         <urn:password>password + security token</urn:password>
      </urn:login>
   </soapenv:Body>
</soapenv:Envelope>

Below is the sample SOAP response:


<soapenv:Envelope 
     xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
     xmlns="urn:partner.soap.sforce.com" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Body>
      <loginResponse>
         <result>
            <metadataServerUrl>
               https://na5.salesforce.com/services/Soap/m/30.0/00D700000008fqn
            </metadataServerUrl>
            <passwordExpired>false</passwordExpired>
            <sandbox>false</sandbox>
            <serverUrl>
              https://na5.salesforce.com/services/Soap/u/30.0/00D700000008fqn
             </serverUrl>
            <sessionId>REMOVED</sessionId>
            <userId>005700000012RyAAAU</userId>
            <userInfo>
               <accessibilityMode>false</accessibilityMode>
               <currencySymbol>$</currencySymbol>
               <orgAttachmentFileSizeLimit>5242880</orgAttachmentFileSizeLimit>
               <orgDefaultCurrencyIsoCode>USD</orgDefaultCurrencyIsoCode>
               <orgDisallowHtmlAttachments>false</orgDisallowHtmlAttachments>
               <orgHasPersonAccounts>true</orgHasPersonAccounts>
               <organizationId>00D700000008fqnEAA</organizationId>
               <organizationMultiCurrency>false</organizationMultiCurrency>
               <organizationName>REMOVED</organizationName>
               <profileId>00e70000000sEkZAAU</profileId>
               <roleId>00E70000000olJBEAY</roleId>
               <sessionSecondsValid>7200</sessionSecondsValid>
               <userDefaultCurrencyIsoCode xsi:nil="true"/>
               <userEmail>REMOVED/userEmail>
               <userFullName>REMOVED</userFullName>
               <userId>005700000012RyAAAU</userId>
               <userLanguage>en_US</userLanguage>
               <userLocale>en_US</userLocale>
               <userName>REMOVED</userName>
               <userTimeZone>America/Los_Angeles</userTimeZone>
               <userType>Standard</userType>
               <userUiSkin>Theme3</userUiSkin>
            </userInfo>
         </result>
      </loginResponse>
   </soapenv:Body>
</soapenv:Envelope>

NOTE:

The following is important on your succeeding calls using SOAP
  • sessionId: This is the value you would need to pass to succeeding SOAP calls as this proves that you are authenticated.
  • serverUrl:  This will be the URL you will need to post succeeding SOAP calls.
please see my blogpost for doing SOAP integration using Partner WSDL.


17 March 2013

Testing SFDC Web Service using SoapUI

Its not often to that you need to test your custom SFDC web service codes using XML request/response. Usually when you create your own custom web service you just generate the WSDL file, give it to your integrator and his middleware tool will do all of the conversions.

Recently I got challenged by one of my colleague on how I test my web services (just because they could not figure out how they can consume the WSDL file). I told him that I use Eclipse or the Force.com IDE to test if the service are running correctly by executing an anonymous call. This is just ok but you are not really calling your web service using the standard XML request/response. 

So how can you test your web service?

First, you need SoapUI. Its a free tool you can use in PC and Mac.

Second, you need to download your Salesforce WSDL file. You can use either the Enterprise or the Partner WSDL from Setup -> Develop -> API


Third, you create your custom web service logic. This is optional as you can use the standard web service method from the API. In the example below I just created a simple service that returns a string value 'Hello World!' and downloaded its WSDL file.


/* 
    Description: This class is called from SoapUI
*/
global class SimpleService {
     webservice static string sampleService() {
        return 'Hello World!';
    }
}

Fourth, you create a new project in SoapUI and use the WSDL generated from the second step. For this example I used the Enterprise WSDL. 



After the project is created, import the custom service WSDL file by right clicking on the project and selecting 'Add WSDL' context menu. Select the custom web service WSDL.


You should now have two nodes on the project, one for the Enterprise and the other for the custom web service you have coded as below.



Fifth step is to create a login request. Delete all of the values from the <soapenv:Header> section and then add your actual username and password to the appropriate tags like the screenshot below and click the submit icon. It should return with a soap response envelop.



Sixth, use the session Id from the soap response from step 5 and use it on your custom service call.



Click the submit icon and it should update back with the response envelop and thats it, Congratulations!


Please note that I have removed all of the header information except for the session Id which is important.

Additional notes:
- If you have a custom web service with parameters and you need to pass null value on it, Salesforce requires you to remove the parameter node on the request instead of passing a node without a value. This behavior is the same on an outbound message in which Salesforce removes the field on the message if the field is null.