Archive

Posts Tagged ‘Integration’

Salesforce REST API Composite Services

January 17, 2018 Leave a comment

Salesforce has a feature on the REST API called as the Composite Resources. This allows us to build API requests by combining more than one request. Shown below are someĀ  examples of them with Postman (https://www.getpostman.com/). Documentation of Composite Resources can be found here (https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_composite.htm)

The first step is to get the authorization token.

Endpoint : https://login.salesforce.com/services/oauth2/token
Method Type : POST

The body should have form data which has the following : grant_type, username, password, client_id, client_secret. client_id and client_secret are taken from the App created in Salesforce for the integration. See details in the “Setting up Salesforce Connected App” section on this blog post here : https://codesilo.wordpress.com/2017/12/26/spring-boot-rest-api-integration-with-salesforce/
Username and Password should be the username and password of the account being used for the API access. Security Token, if enabled, should be concatenated to the password above. API access should be provided to the Profile of this account.
The grant_type is “password”. It is the word password without the quotes and not the actual password of the user account.

Screen Shot 2018-01-17 at 12.53.33 PM
On making the call, we should get the access_token in the response. This access_token is now used in all subsequent calls below. The instance_url from the response is used to create the endpoint in the requests below.

For all calls below we will have the following 2 headers

Authorization : Bearer **accesss_token HERE**
Content-Type : application/json

Note: For the authorization header the value has to be “Bearer” without the quotes followed by a space and the access_token

1. Composite API Call:

Endpoint: https://INSTANCE_URL_HERE/services/data/v41.0/composite/
Method Type: POST

Sample Body:

{
    "allOrNone" : true,
    "compositeRequest" : [{
        "method" : "GET",
        "url" : "/services/data/v38.0/query?q=select id from Account where id='0014600000KPgY8'",
        "referenceId" : "AccountIden"
        },{
        "method" : "GET",
        "url" : "/services/data/v38.0/query?q=select name from Account where id = '@{AccountIden.records[0].Id}'",
        "referenceId" : "TestDataQuery"
    	}
    ]
}

Screen Shot 2018-01-17 at 1.01.38 PM

2. Batch API call:

Endpoint: https://INSTANCE_URL_HERE/services/data/v40.0/composite/batch/
Method Type: POST

Sample Body:

{
    "batchRequests" : [{
        "method" : "GET",
        "url" : "/services/data/v38.0/query?q=select id from Account where id='0014600000KPgY8'"
        },{
        "method" : "GET",
        "url" : "/services/data/v38.0/query?q=select id, name from SalesforceTestData__c where id = 'a0E46000003icvo'"
    	}
    ]
}

Screen Shot 2018-01-17 at 1.02.50 PM

3. SObject Tree API call:
Endpoint: services/data/v40.0/composite/tree/Account
Method Type: POST

Sample Body:

{
"records" :[{
    "attributes" : {"type" : "Account", "referenceId" : "ref1"},
    "name" : "SampleAccount",
    "phone" : "1234567890",
    "website" : "www.salesforce.com",
    "numberOfEmployees" : "100",
    "industry" : "Banking",
    "Contacts" : {
      "records" : [{
         "attributes" : {"type" : "Contact", "referenceId" : "ref2"},
         "lastname" : "Smith",
         "title" : "President",
         "email" : "sample@salesforce.com"
         },{
         "attributes" : {"type" : "Contact", "referenceId" : "ref3"},
         "lastname" : "Evans",
         "title" : "Vice President",
         "email" : "sample@salesforce.com"
         }]
      }
    },{
    "attributes" : {"type" : "Account", "referenceId" : "ref4"},
    "name" : "SampleAccount2",
    "phone" : "1234567890",
    "website" : "www.salesforce2.com",
    "numberOfEmployees" : "100",
    "industry" : "Banking"
     }]
}

Note: In this example we are adding Contacts tp an account and adding another account without a Contact (Reference: https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/requests_composite_sobject_tree.htm#topic-title)

4. SObject Collections:
This is similar to the Tree API call however it does not take child records in the request. This can be used to execute requests on several records at once. It can also be used to retrieve the data (which is different in comparison to tree)
Examples are described well here: https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_composite_sobjects_collections.htm

Spring Boot REST API integration with Salesforce

December 26, 2017 1 comment

This blog covers ways to integrate with Salesforce using REST API.
We will use Spring Boot to authenticate (get access_token and instance_url from Salesforce). Although this can be done using a plain Java Application, we will assume that a real world use case requires a web application to call the services.

The Spring Boot application we create will have have a service exposed through a plain HTTP GET call. The application will call the authentication on Salesforce and use the response from the authentication to make a call to get some data from an Object in Salesforce. In an actual implementation the authentication can be cached and need not be called each time before making an API call to Salesforce. The cache can be refreshed more frequently than the timeout on the session, or, it can be refreshed after the authentication failure exception because of the timeout.

1. Creating the Spring Boot Application

The easiest way to create a starter project is to use Spring STS (https://spring.io/tools). You could also follow the steps here if you don’t want to use STS and want to use some other IDE. (https://spring.io/guides/gs/spring-boot/)

To create the Project in STS, run the install of STS and create a new workspace for yourself. Click on File | New | Spring Starter Project
In the new Window, provide the name of the Project (for this example we give the name SalesforceRESTAPI), group name (com.wordpress.codesilo.salesforce), Artifcat (keep it as is – should have autofilled the name of the Project above), package (com.wordpress.codesilo.salesforce). These can be changed according to your namespace.

Screen Shot 2017-12-22 at 3.53.54 PM

In the next step select “Web” from the dependencies and proceed to create the project. To start the instance, right click on the project and to to Run As | Spring Boot App. This should start the server and you should be able to see the progress in the console. On the browser, go to http://localhost:8080 and you should be presented with a page with a “Whitelabel Error Page” header

Screen Shot 2017-12-22 at 6.08.34 PM

So far, we have created a default Spring Boot Application with “Web” added as a dependency (spring-boot-starter-web dependency). The next step is to add a simple Controller and a class to call the Salesforce API. But before we do that, we will create an object and create an “App” on a Salesforce instance that we want to connect to.

2. Setting up Salesforce Connected App

We will use a new Salesforce Developer Edition Org. Sign up for on here (https://developer.salesforce.com/signup)
Once logged in, go to the Classic mode in Salesforce and then to Setup | Create | Apps

Click “New” on Connected Apps and fill the form in the next page. Add the Connected App Name, API Name and email as required. We don’t need these fields for the integration however. Click on “Enable OAuth Settings” and add the following as the Callback Url “http://localhost”. For selected OAuth Scopes, choose Full Access for now. Change these settings as required later. Save the changes – it should take a few minutes for this to take effect.
In order to create Connected App in Salesforce Lightning see here https://help.salesforce.com/articleView?id=connected_app_create.htm&type=5

You should now be able to get the following information from the Connected App created – Consumer Key, Consumer Secret. If you don’t have a Security Token for your account yet (had you created the Developer Edition instance earlier), go to, “My Profile” and in the Quick Find look for “Reset Security Token”. This should send you a security token to your email. Note: If the “Login IP” ranges for your Profile has been set appropriately, you might not require the security token.

3. Create the Controller on Spring Boot App

We will create a new Class for the controller in the following package. com.wordpress.codesilo.salesforce.controller. The class will take a simple GET request and return the text “home” in the body.

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SalesforceAPIController {

@RequestMapping("/home")
public String getSalesforceObject(){
return "home";
}

}

4. Create the class to make the API call to Salesforce

Create the model class to store the response from the authentication on Salesforce

package com.wordpress.codesilo.salesforce.model;

public class AuthenticationResponse {

private String access_token;
private String instance_url;
private String token_type;
private String issued_at;

public String getAccess_token() {
return access_token;
}
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public String getInstance_url() {
return instance_url;
}
public void setInstance_url(String instance_url) {
this.instance_url = instance_url;
}
public String getToken_type() {
return token_type;
}
public void setToken_type(String token_type) {
this.token_type = token_type;
}
public String getIssued_at() {
return issued_at;
}
public void setIssued_at(String issued_at) {
this.issued_at = issued_at;
}

@Override
public String toString() {
return "AuthenticationResponse [access_token=" + access_token + ", instance_url=" + instance_url
+ ", token_type=" + token_type + ", issued_at=" + issued_at + "]";
}
}

We now create a class (SalesforceAPIService) to make the REST API calls to Salesforce. We first have to make a call to authenticate with Salesforce. (Replace the parameters marked between ** below with appropriate values of your instance/Org)

public AuthenticationResponse login(){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> params= new LinkedMultiValueMap<String, String>();

params.add("username", ** USERNAME HERE **);
params.add("password", ** CONCATENATION OF PASSWORD AND SECURITY TOKEN HERE ** );
params.add("client_secret", ** CONSUMER SECRET FROM CONNECTED APP HERE ** );
params.add("client_id", ** CONSUMER KEY FROM CONNECTED APP HERE **);
params.add("grant_type","password");

HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(params, headers);

RestTemplate restTemplate = new RestTemplate();
ResponseEntity response = restTemplate.postForEntity("https://login.salesforce.com/services/oauth2/token", request, AuthenticationResponse.class);
return response.getBody();;
}

The response from the call above has the token and the instance url that we use in the next call to get the data from an Object.

In the next API call, we will query the Account object to get the Id and Name from the object. We will assume that we will get a specific object by querying based on an Id. Use an Id from your Developer Edition to query and get a result. The response is going to be in json in the following format. Here is the sample:

{
"totalSize": 1,
"done": true,
"records": [
{
"attributes": {
"type": "Account",
"url": "/services/data/v22.0/sobjects/Account/001f4000005WEvpAAG"
},
"Id": "001f4000005WEvpAAG",
"Name": "Burlington Textiles Corp of America"
}
]
}

We need to create the Java Objects to store the response. In order to create the POJO, we can use http://www.jsonschema2pojo.org/

The following classes are to be created for the POJOs

public class AccountResponse {

private int totalSize;
private boolean done;
private List records;

public int getTotalSize() {
return totalSize;
}
public void setTotalSize(int totalSize) {
this.totalSize = totalSize;
}
public boolean isDone() {
return done;
}
public void setDone(boolean done) {
this.done = done;
}
public List getRecords() {
return records;
}
public void setRecords(List records) {
this.records = records;
}

}
public class Attribute{
private String type;
private String url;

public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}

public class Account {
@JsonProperty("attributes")
private Attribute attributes;
@JsonProperty("Id")
private String id;
@JsonProperty("Name")
private String name;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("attributes")
public Attribute getAttributes() {
return attributes;
}

@JsonProperty("attributes")
public void setAttributes(Attribute attributes) {
this.attributes = attributes;
}

@JsonProperty("Id")
public String getId() {
return id;
}

@JsonProperty("Id")
public void setId(String id) {
this.id = id;
}

@JsonProperty("Name")
public String getName() {
return name;
}

@JsonProperty("Name")
public void setName(String name) {
this.name = name;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}

In the class we use to call the API to Salesforce add the following method to get the data from the Account Object.

public AccountResponse getAccountData(String accessToken, String instanceUrl){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + accessToken);
MultiValueMap<String, String> params= new LinkedMultiValueMap<String, String>();

HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(params, headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity salesforceTestData = restTemplate.exchange(instanceUrl+ "/services/data/v22.0/query?q=select Id, Name from Account where Id = '001f4000005WEvp'", HttpMethod.GET, request, AccountResponse.class);
log.info(salesforceTestData.getBody().getRecords().get(0).getName());
return salesforceTestData.getBody();
}

The accessToken and instanceUrl parameters are the values from the AuthenticationResponse above.

5. Remap the Controller class to call the service

We will mark the SalesforceAPIService class with the @Component annotation so that it is available for autowiring in the controller.
We now call the SalesforceAPIService from the controller and pass the response to the service on Spring.

@RequestMapping("/account")
public AccountResponse getSalesforceAccount(){
AuthenticationResponse authenticationResponse = salesforceAPIService.login();
AccountResponse accountResponse = salesforceAPIService.getAccountData(authenticationResponse.getAccess_token(), authenticationResponse.getInstance_url());
return accountResponse;
}

Once we start the server and call go the following url (GET request) http://localhost:8080/account , we get the response from the service call to Salesforce.

Screen Shot 2017-12-25 at 10.45.50 PM.png