Salesforce REST API: Connected Apps & Apex REST Methods

By in
64
Salesforce REST API: Connected Apps & Apex REST Methods

This article assumes you have at least a basic understanding of programming.

What is REST API and Why Should I Use It?

REST API is a beautiful architecture style of handling data between two systems. Its primary focus is simplicity with scalability. But what is REST API? If I pulled out the online dictionary for each acronym, it would be described as follows:

  • REST – “REST is an acronym for REpresentational State Transfer…”[1] or in other words, it’s a style of handling data between two systems.
  • API – “… an application programming interface (API) is a set of subroutine definitions, communication protocols, and tools for building software…”[2]. To put it simply, it’s summarizing code functions which may do complex things.

If you made it past the definitions without falling asleep, congrats! You’re doing better than I did my freshman year of college. That’s a lot of jargon, but there is a simpler way to put it. Think of your car’s gas pedal. It receives an input (foot pressing) and gives an output (vibrations from engine speed) between two systems; you and the car.

Keeping up with the car analogy, it’s generally operated the same way across multiple brands and models. It saves you a lot of effort in getting from point A to B. But behind the scenes, the API (or gas pedal) is doing a lot of complex things to make you move. Imagine being forced to reinvent the car on your own. You may have to earn a degree or two in mechanical engineering. That would be insane! APIs, specifically REST APIs, allow programmers to gain all the benefits of integrating two systems together without having to know all the details behind them.

I’ll use “REST,” “API,” and “REST API” interchangeably to mean the same thing for the rest of this article.

Using APIs is extremely helpful when you want to integrate two systems or perform massive amounts of computing. If you’ve spent any time programming in Salesforce, the first word you have engrained in your mind is “limits.” Salesforce is all about limits in order to protect its multi-tenant architecture. REST allows you to work with larger amounts of data in order to bypass these limits.

Tools Needed

You’ll need the following to get started. I won’t be covering how to install them. The sites related to each should have enough instructional material for their own products.

Limits

Think you could see any of the code before learning about Salesforce’s limits? Ha! Don’t think you’ll get off that easy. Salesforce details their limits here. To summarize it, you get at least 15,000 requests a day and most orgs I’ve dealt with have at least 350,000 call allocations per 24 hours. Salesforce describes, in length, their API reporting limits here, but if you want to quickly check your org’s limit, simply to go SetupQuick Find type “Company Information” > “API Requests, Last 24 hours”.

If you want to be extra safe with your org, check out API Usage Notifications so you can stay on top of things long term. Everyone loves automation.

Setup: Connected Apps

Many systems call it by different names. Salesforce calls it a Connected App. All it does is provide a “hall pass” to authorized systems/applications to access the database. In this case, the database is Salesforce. You get to define where the requests can come from and how much data it has access to.

To start, you must go into the setup of your Salesforce org. In the quick find, type “App Manager” until the option shows up.

        From there, the “New Connected App” button on the right.

The form requires a name and email. Make sure to “Enable OAuth Settings” in the API section. The callback URL can be anything you want, but if you want to go with a ‘default’, use “https://login.salesforce.com/services/oauth2/callback”. Use the “Full Access” option in the OAuth Scope for now. Ideally, stricter security would be used, but this is for learning purposes with the simplest setup possible.

When you click “save”, you will be greeted with this message. This would be a great time to get a Coffee.

Once you’ve clicked “Continue,” your screen will look like this. You’ll be using the Consumer Key and Secret Key later.

Before we move on, make sure to do this or else the following steps won’t work. Click “Manage” and then “Edit Policies.” Change “IP Relaxation” to Relax IP Restrictions and save.

Setup: Postman

Now we’re cooking with gas! Once your Postman is launched, create a collection which will house all the different queries we’re going to make. If you’re looking for a fast solution, all the examples shown below are here.

Within the Collection, create a Request:

The request type needs to be set to “POST” or else this won’t work.

The URL to get a token is as follows. Replace the bold parameters with their respective values from both your user and the Connected App.

  • Production
    • https://login.salesforce.com/services/oauth2/token?grant_type=password&client_id=ConsumerKey&client_secret=ConsumerSecret&username=SalesforceUserName&password=SalesforcePassword
  • Sandbox (Full, Partial, Dev)
    • https://test.salesforce.com/services/oauth2/token?grant_type=password&client_id=ConsumerKey&client_secret=ConsumerSecret&username=SalesforceUserName&password=SalesforcePassword

When you’re done, it should look a lot like this:

Moment of truth, click the “Send” button and you should see information like this below:

The two pieces of data you will want to take out of this right now is the “access_token” and “instance_url” values. The access token is the special “hall pass” we discussed early. It lets you do whatever you want in the Salesforce system (barring security settings made in the Connected App). The instance URL helps point Salesforce to the right server when communicating with your programs.

Congratulations! You just connected with the system successfully, and now we can communicate with Salesforce from a third-party application. The next section will cover how to query Salesforce and implement advanced techniques for complex solutions with relatively little code.

Testing Queries in Postman

Now that we have a token, lets check out what we can do. To start, we’ll go with getting a record by Id.

Create another request but this time make it a “GET” type.

The structure of the URL used is as follows. Update the sections in bold to the appropriate values.

  • https://instanceurl/services/data/v43.0/sobjects/Objectname/Id

In this example, I’m going to get SMG3’s Account in our system. The text would be:

  • https://smg3login–Dev.cs47.my.salesforce.com/services/data/v43.0/sobjects/Account/0012a00000ZR1YzAAL

Next, you’ll have to copy the Access Token to the Authorization tab. Select “bearer token” and paste the token in the text field. Click “Send” and see the results.

Testing Apex REST Methods

Now that we have a successful connection to Salesforce through a Connected App, lets look at something more complex. Apex has a set of REST methods which allow you to define logic endpoints. This can be incredibly helpful to simplify and standardize your logic. I prefer Apex REST over writing large and complex SOQL queries in my “standard” REST requests. In addition to reducing overall complexity, I find it to be a best practice to keep as much logic centralized within Salesforce as possible.

In this example, we’re going to build the following requirements. This example is simple to fulfill in Apex but overly difficult in standard REST (or downright impossible). Salesforce provides documentation on how to implement REST methods in Apex but I’m going to provide a simplified explanation.

  • Get the name of Accounts with a predefined number of Contacts. No more, no less. For instance, if I pass a parameter of 3 (three), it should only return Accounts which have 3 Contacts associated with it.
  1. @RestResource(urlMapping=’/AccountCountExample/*’)  
  2. global class ApexRestExample {  
  3.   
  4.     @HttpPost  
  5.     global static List<Account> getAccountCount(Integer contactCount)   
  6.     {  
  7.      
  8.     }  
  9. }  

Lets breakdown this skeleton.

  1. @RestResource(urlMapping=’/AccountCountExample/*’)  

This provides Salesforce with the knowledge that anytime someone makes a REST request with this path, its talking about this class.

  • global class ApexRestExample {  

Anytime you make a class for REST, you must set it to global. This allows any other part of the system to access the methods inside.

  • @HttpPost  
  • global static List<Account> getAccountCount(Integer contactCount)   

@HttpPost is an annotation of Salesforce’s Apex REST Methods to signify anytime the REST request is of type “POST”, then use this method. You can only have one of each REST type in a class (e.g. GET, POST, PUT, etc)

In addition, we’re defining a name for the function and number of parameters (contactCount) and return type (List<Account>) desired for the function to work correctly.

Below is a full example of what the Apex class would like plus comments explaining each subsection.

  1. @RestResource(urlMapping=’/AccountCountExample/*’)  
  2. global class ApexRestExample {  
  3.   
  4.     @HttpPost  
  5.     global static List<Account> getAccountCount(Integer contactCount)   
  6.     {  
  7.         // List which will contain the final result  
  8.         List<Account> listOfAccountsToReturn = new List<Account>();  
  9.   
  10.         // Query to get all Accounts with at least one Contact  
  11.         List<Account> listOfAccounts = ([SELECT Id,   
  12.                                             Name,  
  13.                                             (SELECT Id  
  14.                                              FROM Contacts)  
  15.                                         FROM Account  
  16.                                         WHERE Id IN (SELECT AccountId FROM Contact)]);  
  17.           
  18.         // Cycle through all the Accounts and make sure the Contact  
  19.         // Count matches the actual number of Contacts  
  20.         for(Account tempAccount : listOfAccounts)  
  21.         {  
  22.             Integer count = 0;  
  23.               
  24.             for(Contact tempContact : tempAccount.Contacts)  
  25.             {  
  26.                 count++;  
  27.             }  
  28.   
  29.             if(count == contactCount)  
  30.             {  
  31.                 listOfAccountsToReturn.add(tempAccount);  
  32.             }  
  33.         }  
  34.   
  35.         return listOfAccountsToReturn;  
  36.     }  
  37. }  

One of the big reasons why I prefer this methodology is so I can write simple Test Classes such as below. It increases my system’s coverage and ensure stability in the logic itself. The class provides both

  • 100% code coverage and
  • three separate tests
    • (1) one Account with one Contact
    • (2) one Account with two Contacts
    • (3) a check to make sure no results if there isn’t an Account with three Contacts.
  1. @isTest  
  2. public class ApexRestExampleTest {  
  3.   
  4.     @TestSetup  
  5.     static void makeData()  
  6.     {  
  7.         // One Account with a single Contact  
  8.         Account tempAccount1 = new Account();  
  9.         tempAccount1.Name = ‘ApexRestExampleTest1’;  
  10.         insert tempAccount1;  
  11.   
  12.         Contact tempContact1 = new Contact();  
  13.         tempContact1.AccountId = tempAccount1.Id;  
  14.         tempContact1.LastName = ‘ApexRestExampleTest1’;  
  15.         insert tempContact1;  
  16.   
  17.         // One Account with two Contacts  
  18.         Account tempAccount2 = new Account();  
  19.         tempAccount2.Name = ‘ApexRestExampleTest2’;  
  20.         insert tempAccount2;  
  21.   
  22.         Contact tempContact2 = new Contact();  
  23.         tempContact2.AccountId = tempAccount2.Id;  
  24.         tempContact2.LastName = ‘ApexRestExampleTest2’;  
  25.         insert tempContact2;  
  26.   
  27.         Contact tempContact3 = new Contact();  
  28.         tempContact3.AccountId = tempAccount2.Id;  
  29.         tempContact3.LastName = ‘ApexRestExampleTest2’;  
  30.         insert tempContact3;  
  31.     }  
  32.       
  33.     public static TestMethod void testEndpointSingleAccountOneContact()  
  34.     {      
  35.         Test.startTest();  
  36.   
  37.         List<Account> returnedList = ApexRestExample.getAccountCount(1);  
  38.   
  39.         System.assertEquals(1, returnedList.size());  
  40.   
  41.         Account tempAccount = returnedList.get(0);  
  42.   
  43.         System.assertEquals(‘ApexRestExampleTest1’, tempAccount.Name);  
  44.   
  45.         Test.stopTest();  
  46.     }  
  47.   
  48.     public static TestMethod void testEndpointSingleAccountTwoContacts()  
  49.     {      
  50.         Test.startTest();  
  51.   
  52.         List<Account> returnedList = ApexRestExample.getAccountCount(2);  
  53.   
  54.         System.assertEquals(1, returnedList.size());  
  55.   
  56.         Account tempAccount = returnedList.get(0);  
  57.   
  58.         System.assertEquals(‘ApexRestExampleTest2’, tempAccount.Name);  
  59.   
  60.         Test.stopTest();  
  61.     }  
  62.   
  63.     public static TestMethod void testEndpointSingleAccountThreeContactsZeroResults()  
  64.     {      
  65.         Test.startTest();  
  66.   
  67.         List<Account> returnedList = ApexRestExample.getAccountCount(3);  
  68.   
  69.         System.assertEquals(0, returnedList.size());  
  70.   
  71.         Test.stopTest();  
  72.     }  
  73. }  

Putting It All Together

Now that we have a client (Postman) and an endpoint with specialized logic (Salesforce Apex), we can put it all together by creating a request.

First, we must make the type of request “POST” in order to match up with the Apex logic

Use the appropriate URL. In this instance, I’m using:

https://smg3login–Dev.cs47.my.salesforce.com/services/apexrest/AccountCountExample/

Then we must define the Content-Type. That’s basically just saying “I’m expecting the response to come back in a specific format”. In this case, we want JSON (JavaScript Object Notation). You make this change by going into the “Headers” tab and setting the key value “Content-Type” to “application/json”.

Lastly, we must define the parameter(s). under the “Body” tab, paste this into it

  1. {  
  2.     “contactCount” : “1”  
  3. }  

Notice the name of the value matches the Apex parameter name. That’s intentional and what you need to do for the parameter to get passed along. For this example, I’m just looking for Accounts with a single Contact related to it, hence the value of “1”.

Click send and see the response below:

Apex natively provides their data in a JSON structure when its returned. In this case, we see both the Account data

And the underlying Contact found in the subquery we did in Apex

That’s it! Now you’re equipped with the knowledge to produce complex integrations between two different systems.

Source code

As with any code tutorial on the internet, I’ve created a Github repository containing all the different components built here. Feel free to download or Fork it for your own purposes.


[1] https://restfulapi.net/

[2] https://en.wikipedia.org/wiki/Application_programming_interface


54321
(0 votes. Average 0 of 5)
Leave a reply

Your email address will not be published. Required fields are marked *