How to integrate Salesforce API with Spring Boot Application

This blog post provides a step-by-step guide on how to integrate Salesforce, a leading CRM platform, with a Spring Boot application. It covers setting up a Salesforce account, creating a Connected App, and developing the Spring Boot application to access Salesforce data via REST API calls.

GraphQL has a role beyond API Query Language- being the backbone of application Integration
background Coditation

How to integrate Salesforce API with Spring Boot Application

Salesforce, a leading customer relationship manager (CRM) platform, is used by millions for their business or personal needs. A few of Coditation’s customers use Salesforce: customize it and then treat it as a single source of truth within their organization. Working with them, our customers, essentially asks us to integrate Salesforce with our newly developed proxy-servers which fetch/send data from/to mobile applications or web applications. 
Basically, Salesforce holds business data for many of our customers and thus instead of transferring or replicating the huge data to some other data sources, it is better to make use of the Salesforce services that allows us to interact with the data readily available with it.
This is not a cumbersome process but definitely if not followed the right manner will lead to security leak or show performance issues and thus sharing a step-by-step approach that may help you.

Setting up the Salesforce Account :

This is the first and very important step to be able to interact with the Salesforce APIs.
We assume that you have a Salesforce account.
If you don’t have one please follow this:
https://developer.salesforce.com/signup to create a new Salesforce account.

Creating a Connected App within the Salesforce Account :

Basically, a Connected App acts as a bridge between the Salesforce services and the external third-party applications. So, in our case our Spring Boot Application is one such third-party application for Salesforce. Once we create the Connected App within the Salesforce instance, we will get the credentials to generate access tokens from to access the Salesforce services and data. Please follow below steps to create the Connected App :

  1. Log into your Salesforce instance and navigate to Setup section
  2. Find the ‘Apps’ on left side section → Expand Apps → Click on Manage Apps
  3. Click on ‘New Connected App’ tab
  4. Fill in the form and click on Save button
  5. Verify the app creation and make a note of the Consumer Key and Consumer Secret for future reference.

At this point, we are ready with the Salesforce part for our integration.
Now let’s proceed with the creating our Spring Boot Application

Creating Spring Boot Application :

We are using a maven based spring boot application for this integration. Below are the steps we took to create the application :

  1. Create Spring Boot Application using Spring Initializr with below dependencies :

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.7.9-SNAPSHOT</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>SalesforceIntegrationApp</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>SalesforceIntegrationApp</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>11</java.version>
		<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<build>
  <plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>
	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
		<repository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
			<releases>
				<enabled>false</enabled>
			</releases>
		</repository>
	</repositories>
	<pluginRepositories>
		<pluginRepository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</pluginRepository>
		<pluginRepository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
			<releases>
				<enabled>false</enabled>
				</releases>
		</pluginRepository>
	</pluginRepositories>
</project>


  1. Now let’s add a handler method in the controller for getting Salesforce accounts as below. We have defined the endpoint as “/accounts“ :

package com.example.SalesforceIntegrationApp.classes;

import java.util.Collections;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Controller {

	@Autowired
	private AccountService accountService;

	@GetMapping(value = "/accounts")
	public Map getAccounts() {
		try {
			return accountService.getAccountList();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		return Collections.emptyMap();
	}
}

  1. Now we will create a class AccountService that we have autowired in the Controller as below : 

package com.example.SalesforceIntegrationApp.classes;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AccountService {

	@Autowired
	private SalesforceDataService salesforceDataService;

	public Map getAccountList() {
		String query = "SELECT Id, Name FROM Account";
		return salesforceDataService.getSalesforceData(query);
	}

}

  1. And, finally we will create a class SalesforceDataService which is responsible for making SalesforceAPI calls. This class contains the implementation to consume the Salesforce APIs. We have used RestTemplate to consume the Salesforce APIs. It utilizes the access token generated by a singleton class SalesforceAuthenticator which we will see further to access the secured endpoints of Salesforce :

package com.example.SalesforceIntegrationApp.classes;

import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

@Service
public class SalesforceDataService {

	public Map getSalesforceData(String query) {
		SalesforceAuthenticator salesforceAuthenticator = SalesforceAuthenticator.getSalesforceToken();
		try {
			RestTemplate restTemplate = new RestTemplate();
			String encodedQuery = URLEncoder.encode(query, StandardCharsets.UTF_8.toString());
			final String baseUrl = salesforceAuthenticator.instanceUrl + "/services/data/v52.0/query/?q="
					+ encodedQuery;
			URI uri = new URI(baseUrl);

			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
			headers.add(HttpHeaders.AUTHORIZATION, String.format("Bearer %s", salesforceAuthenticator.accessToken));
			HttpEntity<?> request = new HttpEntity<Object>(headers);
			ResponseEntity<Map> response = null;
			try {
				response = restTemplate.exchange(uri, HttpMethod.GET, request, Map.class);
			} catch (HttpClientErrorException e) {
				System.out.println(e.getMessage());
			}
			return response.getBody();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		return Collections.emptyMap();
	}
}

  1. You will notice that we have used the SalesforceAuthenticator class to get the Salesforce access token. Basically it is a singleton class that initializes and maintains a salesforce access token by logging into a salesforce instance. It makes use of the consumer id and consumer secret that we generated after adding a connected app :

package com.example.SalesforceIntegrationApp.classes;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

public class SalesforceAuthenticator {
	
    private static SalesforceAuthenticator salesforceAuthenticator = null; 
    public static String accessToken;
    public static String instanceUrl;
    
    private SalesforceAuthenticator() {
    	try {
    		final String baseUrl = "<Your-instance-URL-goes-here>";
			URI uri = new URI(baseUrl);
HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

			MultiValueMap<String, String> params= new LinkedMultiValueMap<String, String>();
			params.add("username", "<Your-username>");
			params.add("password", "<Your-password>");
			params.add("client_secret", "<Your-consumer-secret>");
			params.add("client_id", "<Your-consumer-id>");
			params.add("grant_type","password");
			
			HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(params, headers);
			
			RestTemplate restTemplate = new RestTemplate();
			ResponseEntity<Map> response = restTemplate.postForEntity(uri, request, Map.class);
			
			Map<String,String> responseBody = response.getBody();
	
			accessToken = responseBody.get("access_token");
			instanceUrl = responseBody.get("instance_url");
    	}catch(Exception e) {
        	System.out.println(e.getMessage()); 		
    	}
    }
 public static SalesforceAuthenticator getSalesforceToken() 
    { 
        try {
        	if (salesforceAuthenticator == null) 
	        { 
        		salesforceAuthenticator = new SalesforceAuthenticator();
	        	return salesforceAuthenticator;
	        }else {
	        	return salesforceAuthenticator;
	        }
        }catch(Exception e) {
        	e.printStackTrace();
        	System.out.println(e.getMessage());
        }
        return null;
    }
}

  1. At this point we are now done with the Spring boot applications as well. Now let's test this using postman :

As you can see, we are now able to get the Account records from Salesforce. 
You can try for other salesforce objects like Contacts, Leads, etc.

Conclusion :

Following the above approach to integrate Salesforce APIs with your Spring Boot application can enable your business to automate several processes and enhance customer experience.
This is just an overview of how we can achieve the integration programmatically. You can explore more with the help of Salesforce official API documentation.

Hello There, I am Sachin Sonone, a software developer who loves tackling complex problems. When I'm not coding, you may often find me engrossed in a game of chess. I thrive on challenging work that pushes my problem-solving and technical skills to the limit.

Want to receive update about our upcoming podcast?

Thanks for joining our newsletter.
Oops! Something went wrong.