SalesForce API calls to fetch data
My exploration on SalesForce APIs had revealed a couple of approaches to fetch data from SalesForce. The main ones are listed below
SOAP Api
Rest calls
Bulk API
Data Loader
Rest calls
Bulk API
Data Loader
Before we begin, there are a set of prerequisites that you need to get done in order to run the sample or interact using the SalesForce API's.
Prerequisites:
User Name
Password
Security Token (needed for the Api calls as the password is considered as password+security token)
Client Secret (Required for REST Call)
Client Id (Required for REST Call)
Call Back (This is required if we are authenticating from the web, else if we have a console application this could be some dummy value)
You can register for a developer license in case you don't have a user name and password at https://login.salesforce.com/.
Now let's take a look at each of the options available.
SOAP API
This is really an easy and fast way to query data from SalesForce. But is has got some serious drawbacks. Main ones being the limitations in the number of records that are fetched. The current limit is 2000 records per call. You will also need to consider the number of calls that are being made to SalesForce as there is a usage limit for each instance or Org based on the number of requests made. You need to tread with care when you have a large set of data to be retrieved.
The example shown is mainly a console application used to retrieve data from Sales Force
Steps:
1. Create a console application
2. Add reference to SalesForce Service
You can add reference to the SalesForce service in two ways. Either directly browsing to the wsdl url or download the wsdl and adding it.
Follow the steps shown below to add the reference directly
Click on “Add Service Reference”
Click Advanced
Click “Add Web Reference”
Type the corresponding PARTNER wsdl(my example it was https://na15.salesforce.com/soap/wsdl.jsp) url in the URL and give an appropriate name to your service. Then click “Add Referece”
One important thing to note here is that you need to add a “web reference” itself. If you add a “Service Reference” the proxy class generated from the WSDL is entirely different.
Where can I get the WSDL?
Once you login to your sales force service (http://login.salesforce.com), navigate to “Set Up” from the user name drop down menu
Click on Develop > API in the left hand navigation
You can see the different options for generating WSDL.
You have either the choice of choosing “Enterprise WSDL” or “Partner WSDL” or “APEX WSDL”
Enterprise WSDL is useful when you want to have a proxy class that is tightly coupled to the schema you have built in sales force. You need to re-add the WSDL if you have changed the schema in sales force.
e.g. Dim account As Account = CType (qr.records(i), Account)
You can work directly with the Account entity and its fields if you have a reference to Enterprise WSDL.
The more generic one is the Partner WSDL,which is a loosely typed association. Here you will need to work on the generic object sObject to go through the data.
e.g Dim record As sForceService.sObject = qr.records(i)
3. Login to salesForce service:
You will need username and password. Password comprises of password + the security token. So if your password is “abcd” and token is “EFGH” then the password to be passed to the service is “abcdEFGH”.
' Create the binding to the sforce servics
bindingService = New sForceService.SforceService
' Set the time out valie
bindingService.Timeout = 60000
Dim loginRes As sForceService.LoginResult = bindingService.login(userName, password)
4. Assign the session Id to the SOAP header for subsequent calls:
This is required if you need to make further calls to the API service.
'Create a new session header object and set the session id to that returned by the login
bindingService.SessionHeaderValue = New sForceService.SessionHeader
bindingService.SessionHeaderValue.sessionId = loginRes.sessionId
5. Get the new url for you org:
Once the login succeeds you need to change the endpoint url of you service to the new value returned after successful login.
'Change the binding to the new endpoint
bindingService.Url = loginRes.serverUrl
Initialize the forceService object. Execute the query method of the SforceService object.
'Set the query option, batch size (maximum value allowed is 2000, beyond this value it
'gives and INVALID_BATCH_SIZE error;
Dim results As sForceService.QueryResult = Nothing
bindingService.QueryOptionsValue = New sForceService.QueryOptions
bindingService.QueryOptionsValue.batchSize = 2000
bindingService.QueryOptionsValue.batchSizeSpecified = True
'Run the qquery
results = bindingService.query("select FirstName, LastName from Contact")
Once you get the results you get loop through the results and get the column values.
For i As Integer = 0 To results.records.GetUpperBound(0)
Dim record As sForceService.sObject = results.records(i)
Next
You will need to check if there are more results to be fetched. In that case you need to call the queryMore option with the current location of the returned results. The queryMore picks up the last record id and does a new fetch from that position.
If results.done Then
bContinue = False
Else
results = bindingService.queryMore(qr.queryLocator)
End If
6. Done
Below is the required functions needed to call using the SOAP API
' /*
'* login sample
'* Prompts for username and password, set class variable binding
'* resets the url for the binding and adds the session header to
'* the binding class variable
'*/
Private Function login() As Boolean
Console.Write("Enter user name: ")
Dim userName As String = Console.ReadLine()
If userName.Length = 0 Then
Return False
End If
Console.Write("Enter password: ")
Dim password As String = Console.ReadLine()
If password.Length = 0 Then
Return False
End If
'//Provide feed back while we create the web service binding
Console.WriteLine("Creating the binding to the web service...")
' Create the binding to the sforce servics
bindingService = New sForceService.SforceService
' Set the time out valie
bindingService.Timeout = 60000
'//Attempt the login giving the user feedback
Console.WriteLine("LOGGING IN NOW....")
Try
Dim loginRes As sForceService.LoginResult = bindingService.login(userName, password)
Catch e As System.Web.Services.Protocols.SoapException
'// This is likley to be caused by bad username or password
Console.Write(e.Message & ", please try again." & vbCrLf & vbCrLf & "Hit return to continue...")
Console.ReadLine()
Return False
Catch ex As Exception
'// This is something else, probably comminication
Console.Write(ex.Message & ", please try again." & vbCrLf & vbCrLf & "Hit return to continue...")
Console.ReadLine()
Return False
End Try
Console.WriteLine(vbCrLf & "The session id is: " & loginRes.sessionId)
Console.WriteLine(vbCrLf & "The new server url is: " & loginRes.serverUrl)
'Change the binding to the new endpoint
bindingService.Url = loginRes.serverUrl
'Create a new session header object and set the session id to that returned by the login
bindingService.SessionHeaderValue = New sForceService.SessionHeader
bindingService.SessionHeaderValue.sessionId = loginRes.sessionId
Debug.WriteLine(loginRes.sessionId)
loggedIn = True
Return True
End Function
Private Sub querySample()
'Verify that we are already authenticated, if not
'call the login function to do so
If Not loggedIn Then
If Not login() Then
Return
End If
End If
'Set the query option, batch size (maximum value allowed is 2000, beyond this value it
'gives and INVALID_BATCH_SIZE error;
Dim results As sForceService.QueryResult = Nothing
bindingService.QueryOptionsValue = New sForceService.QueryOptions
bindingService.QueryOptionsValue.batchSize = 2000
bindingService.QueryOptionsValue.batchSizeSpecified = True
Try
'Run the qquery
results = bindingService.query("select FirstName, LastName from Contact")
'create a looop control variable for the loop & 1 behavior
Dim bContinue As Boolean = True
Dim loopCounter As Integer = 0
While bContinue
'process the query results
loopCounter += 1
Console.WriteLine(vbCrLf & "Results Set " &Convert.ToString(loopCounter) & " - ")
For i As Integer = 0 To results.records.GetUpperBound(0)
Dim record As sForceService.sObject = results.records(i)
Dim fName As String = getFieldValue("FirstName", record.Any)
Dim lName As String = getFieldValue("LastName", record.Any)
If fName Is Nothing Then
Console.WriteLine("Contact " & (i + 1) & ": " & lName)
Else
Console.WriteLine("Contact " & (i + 1) & ": " & fName & " " & lName)
End If
Next
'handle the loop + 1 problem by checking to see if the most recent queryResult
'set is
If results.done Then
bContinue = False
Else
results = bindingService.queryMore(results.queryLocator)
End If
End While
Console.WriteLine(vbCrLf & "Query succesfully executed.")
Console.Write(vbCrLf & "Hit return to continue...")
Console.ReadLine()
Catch ex As Exception
Console.WriteLine(vbCrLf & "Failed to execute query succesfully, error message was: " & vbCrLf & ex.Message)
Console.Write(vbCrLf & "Hit return to continue...")
Console.ReadLine()
End Try
Private Function getFieldValue(ByVal fieldName As String, ByVal fields() AsSystem.Xml.XmlElement) As String
Dim returnValue As String = ""
If Not fields Is Nothing Then
For i As Integer = 0 To fields.GetUpperBound(0)
If fields(i).LocalName.ToLower().Equals(fieldName.ToLower()) Then
returnValue = fields(i).InnerText
End If
Next
End If
Return returnValue
End Function
Thats all for the call using SOAP API. Watch this space for updates on REST and the BULK API.