Read time: 7 minutes
Introduction to Force.com Rest API
The scope of this article is to better understand how Force.com REST API works and how to use this powerful Web services API within a scala application. One of the most common and easily way to achieve one way sync of data from your application to Salesforce is integrating Salesforce REST API in your app. Using the API requires basic familiarity with software development, web services, and the Salesforce user interface. Why using REST API? Well, because it’s a powerful, convenient, and simple Web services API, and specially because this technology is based on JSON not XML.
Creating new endpoint in Salesforce
Whenever we use an API, safety comes first. Salesforce uses the OAuth protocol to allow users of applications to securely access data without having to reveal username and password credentials. In this article, the authentication method provides a refresh token that can be used to obtain a new access token.
First step before using REST API, setting up an application as a connected app in the Salesforce organization is needed. For that use the following steps:
In Salesforce create a new connected app from Setup > Create > Apps > Connected Apps > New
1. Check Enable OAuth Settings
2. Add a Callback URL
3. Check Use digital signatures and upload your *.crt file containing your app signature
4. Add to Selected OAuth Scopes:
5. Access and manage your data (api)
- Allow access to your unique identifier (openid)
- Perform requests on your behalf at any time (refresh_token, offline_access)
- Full access (full)
Notes:
- Adding only “Full access (full)” won't be enough for OAuth Scopes
- Callback URL doesn't need to be functional
Scala implementation
My application is written in scala using play framework. So, the following code sample will have marks of the framework I use. Also take note that I won’t focus on receiving the access token needed as Authorization header for every call to Salesforce API, because this is not the aim of my article.
Creating a trait that will deal with all your call through Force.com REST API, seems to be the best way to start with. Working with framework mentioned above, let’s inject first WS Client.
trait SalesforceAuthenticatedRequest { private val injector = new GuiceApplicationBuilder().injector() private val ws: WSClient = injector.instanceOf[WSClient] }
After login to Salesforce, the response will be a JSON that can be validated as
case class SalesforceLoginResponse( access_token: String, instance_url: String, id: String, token_type: String, scope: String )
Access_token is needed to be set up in header as
"Authorization" -> "Bearer "+ access_token
Instance_url Identifies the Salesforce instance to which API calls should be sent. This URL, will be used in our application whenever a call to Force.com REST API is made.
Let’s create a general method named “makeAPIcall” which we shall call every time we want to make a call to Salesforce Rest API. This method can be used to make GET/POST/PATCH/DELETE calls. The body looks like
def makeAPICall(url: String, m: String, b: JsValue, h: List[(String, String)]): Future[WSResponse] = { val call = ws.url(url).withHeaders(h:_*).withBody(b).withMethod(m).execute() call.onComplete{ case Success(res) => Logger.info("Success!") case Failure(e) => Logger.error("Error!") } call }
Note that the url is made of more elements and looks like:
instance_url + "/services/data/v39.0" + your_route
your _route element is also very important and configurable, and I will describe it with examples a little bit later.
m: String parameter represents the method used for WSClient. This parameter can be one from the list: “GET”, “POST”, “PATCH”, “DELETE”.
b: JsValue parameter should be a JSON object used for “POST” and “PATCH” calls. For “GET” calls, this parameter could be an empty JSON (ex. Json.obj() )
h: List [(String, String)] is last parameter, and represents a list with all the headers required. I always add Authorization method, so don’t be misleaded on upcoming examples, if I add no headers whenever I called the above function. For this I have one other function that looks like:
private def addHeaders(headers: List[(String, String)]): List[(String, String)] = { List(("Content-Type", "application/json"), ("Authorization", "Bearer " + accessToken.get.accessToken)) ::: headers }
When using Force.com REST API you can:
- Get data from salesforce
- Insert a record
- Update a secord
- Upsert up to 25 records
- Delete a record
Getting data from salesforce can be done in 2 ways: either using sobjects metadata or getting data with SOQL query. A function for first case will look like
def getCustomFields(table: String, columnName: String, externalId: String, fields: List[String]) = { val route = "/sobjects/" + table + "/" + columnName + "/" + externalId +"?fields=" + fields.mkString(",") makeAPICall(route, "GET") }
As I have promised regarding your_route element described in “makeAPIcall” function, this is how I used to create the url parameter. For example, if I want to have id and email from Contacts after a known externalID, I will simply call:
getCustomFields("Contact", "external_id__c", "1234", List("id","email") )
Same result can be achieved using a SOQL query for having id and email from same record.
def getSOQLResult = { val querySOQL = "SELECT+id,email+from+Contact+where+external_id__c=1234" val route = "/query?q=" + querySOQL makeAPIcall(route, "GET") }
Of course, this second method can be customized to have same parameters as the first, so that it can be used for multiple purposes. This is just an example having same result as my first method.
For inserting a record I used a JsObject, meaning that the body send through Force.com REST API will be a JSON. For example a JSON for inserting a new account can look like:
{ "Name": "MyAccount" }
In my scala example I used Json library from play framework.So for me creating a JSON in scala will look like:
val body = Json.obj("name" -> "MyAccount")
A simple function can be customized so, we can insert a record,using our “makeAPIcall” function, and could look like
def insert(table: String, body: JsObject) = { val route = "/sobjects/" + table + "/" makeAPIcall(route, "POST", body) }
Now, if the insert function was so simplistically implemented, can update be much more difficult? The answer is
def update(body: JsObject, table: String, sfId: String) = { val route = "/sobjects/" + table + "/" + sfId makeAPIcall(route, "PATCH", body) }
In my case I refer to sfId as the Salesforce id of the record. One interesting thing to know, is that within Force.com REST API we can update a record by an externalID. As an example for updating a contact,the route can look like:
val route = "/sobjects/Contact/external_id__c/1234"
One of the powerful feature of the Salesforce REST API, in my opinion, is the upsert feature.This involves using SObject Rows by External ID resource to create records or update existing records based on the value of a specified unique external ID field.
def upsert(tableName: String, externalIdColumnName: String, externalId: String, body: JsObject) = { val route = "/sobjects/" + tableName +"/" + externalIdColumnName + "/" + externalId makeAPIcall(route, "PATCH", body) }
Deleting a record can be done by it’s Salesforce id or external id. In my case I use the method knowing it’s sfId
def deleteRecord(table: String, sfId: String) = { val route = "/sobjects" + table + "/" + sfId makeAPIcall(route, "DELETE") }
One other powerful feature is batch updating. This method allows you to update up to 25 records in one call. A batch request body describes a collection of subrequests to execute with the Batch resource. Actually, we send a JSON array to Salesforce,where each element of the array can look like
val url = "/v39.0/sobjects/Contact/email/" + email Json.obj( "method" -> "PATCH", "url" -> url, "richInput" ->contactJson )
Note that “richInput” is also a JSON, and represents,in my case, the contact that will be updated. The one and only “makeAPIcall” method, is surprisingly used here also.
def batchRequestUpdate(body: JsValue) = { val route ="/composite/batch" makeAPIcall(route, "POST", body) }
Tips
- While implementing this, I encountered lots of issues, so I have some tips for you:
- When creating your Salesforce OAuth App, callback URL doesn't need to be functional
- For requesting access_token, you have to call as login URL either https://test.salesforce.com/ for sandbox, or https://login.salesforce.com for prod.
- Email address can be used as an externalID for Contacts
- Batch request method does not support updating an amount greater than 25 records
- Batch request method can update at the same time records for multiple tables (Account, Contact, etc)
Conclusions
Salesforce REST API provides a powerful, convenient, and simple Web services API for interacting with Force.com.