Of all the development periods I have seen over 30 years in building applications and features, RESTful API the design model is my favorite. Before the RESTful approach, I always felt like something was missing when developing web applications.

My worries calmed down when I attended the Gartner Business Architecture Meeting in 2008. The SOAP v REST session in particular was not only informative and fun, it opened my eyes. I walked away from wanting to understand more about RESTful APIs and soon started experimenting with this new design model during my personal time.

A job change was required before I officially started building RESTful APIs – a change that is now more than a decade old. To this day, I am awakened when I find an impressive API. In fact, an example can be found in my recent publication on marqeta API for processing payments:

Take advantage of Marqeta to build a payment service in Spring Boot

About Salesforce APIs

It should come as no surprise to readers of my previous releases that I am quite impressed with the RESTful APIs offered by Salesforce. In fact, I’m in the middle of a series called “Using Salesforce without Salesforce“What’s possible is a full-featured RESTful API that developers can use to meet their needs.

Just a moment ago, Salesforce developers The site has been redesigned to provide a much better experience for developers who want to use the available APIs. Seeing this kind of activity reinforces my belief that Salesforce puts a lot of value on IT professionals who make Salesforce part of their development software.

Whenever I have the opportunity to integrate or simply use the Salesforce APIs, I look forward to engaging. Anyway, I’ve set out to learn something new that will lead to better APIs for my customers and clients – even those who aren’t connected to the Salesforce platform.

Combined requests

After viewing a presentation combined requests Philippe Ozil, I immediately noticed the value of the combined requests approach, and I can’t wait to get to share it with my readers.

So what are combined requests?

In the Salesforce environment:

Combination requests execute a series of REST API requests in a single call. The result of the original request can be used with the input of the next request. Request responders and HTTP states are returned in one response.

As a result, the entire set of requests is counted one call towards your API boundaries, which all developers using the Salesforce ecosystem should be aware of when building integrations and applications.

Each sub-request of a combined request has httpStatusCodethat maps HTTP status code values ​​used in normal RESTful communication.

A simple combination request example

Salesforce a contact object associated with account object. In addition, each contact can contain a corresponding one individual object.

Before merged requests exist, API developers must first POST a new account object and then use the corresponding ID of the new account to submit the new connection object. As a result, the two calls would be used against the underlying organization’s API restrictions in Salesforce.

Using combination requests, one POST can be made for both destinations. Below is an example of a payload:

{
"compositeRequest" : [{
  "method" : "POST",
  "url" : "/services/data/v52.0/sobjects/Account",
  "referenceId" : "refAccount",
  "body" : { "Name" : "Doe’s Widgets" }
  },{
  "method" : "POST",
  "url" : "/services/data/v52.0/sobjects/Contact",
  "referenceId" : "refContact",
  "body" : { 
    "FirstName" : "John",
    "LastName" : "Doe",
    "AccountId" : "@{refAccount.id}"
    }
  }]
}

In this example, a new account is created for “woman widgets” and the underlying ID is used to create a new contact for “John Doelle”. The two are combined using @{refAccount.id} which has been established referenceId account assets (line 5).

In fact, it might be possible to create a “unique” object for a John Doe contact using the same approach to determine attributes such as date of birth and current occupation. We will implement this scenario a little later.

You may be asking yourself, when should I use (and not use) combined requests? The following table is intended as a quick guide to this question:

When Use Combined requests

Combination requests should be used whenever a set of related objects is created or updated.

When Avoid Combined requests

Currently, the unified API allows up to 25 sub-requests per call. Five of these subqueries can be sObject collections or query functions, including Query and QueryAll requests. So creating a new account with more than 25 related contacts would require an alternative approach.

Using a postman to make composite requests

Postman is an API platform for building and using APIs. I started using Postman about six years ago, mainly to validate API models and use GET, POST, PUT, PATCH, and DELETE methods common to RESTful APIs.

The features available to Postman go far beyond my daily needs, including the following:

  • API Tools – extends my basic use to documentation, mocking, testing, and discovery

  • API Archive – provides a central location where teams can share API objects

  • Workspaces – allows you to group standard Postman functions for easy use

  • Advanced Features – Enhances API functionality with search, notifications, reports, alerts, and security alerts

In the remainder of this article, I will use Postman to explore the concept of combined requests for the Salesforce API.

Acquiring a Salesforce organization

Before we can start using federated requests with Salesforce, we need an instance of Salesforce.

In this article, I’m going to use the Salesforce environment I’ve created ”Utilizing Salesforce without Salesforce”A series that includes the steps required to acquire a Salesforce instance (which can be utilized in this article).

If you’d prefer to follow the instructions in Salesforce, you can also start at the following URL:

Create a developer organization

Configuring the postman

Once Postman is installed, we take advantage of a collection of Salesforce APIs located in the public workspace Salesforce developers. The collection includes all the basic functions we need to log in and make our combined requests.

Before making any changes to the collection, we need to move it to our own Postman workspace:

I named my fork “jvc-composite-request” and used the default values ​​for the other options:

Now I have a Salesforce APIs collection in the local Postman workspace:

Login to Salesforce

We are now ready to log in to Salesforce with OAuth 2.0 through Postman. Go to Authorization tab and scroll down until Get a new license key the button is displayed.

The Get a new license key button opens a new browser window so you can log in to Salesforce. Once logged in, a modal will appear that allows access to API requests.

When you’re done, you’ll see a summary screen:

The last step is to copy instance_url value into _endpoint collection variable, which points the Postman workspace to the correct Salesforce organization.

Check Salesforce connections

To confirm the connection to Salesforce through Postman, I decided to use Inquiry request that can be found Salesforce APIs REST folder. Submitting the request resulted in a 200 OK response and a list of Salesforce instance contacts:

Now that we’ve strengthened our connections from Postman to Salesforce, we’re focusing on making composite requests.

Making composite claims against Salesforce

Based on the example above, I would like to create the following items in Salesforce with one composite request for one of my favorite bands, Hurry:

  • Create a new account named Hurry

  • Create a new contact for Rush Geddy Lee

  • Create a new personal record for Geddy Lelle, whose profession is Bass

  • Create a new contact for Rush Alex Lifeson

  • Create a new personal record for Alex Lifeson by profession Guitar

  • Create a new contact for Rush Neil Peart

  • Create a new personal record for Neil Peart by profession Drums

The payload of the combined request API is as follows:

{
   "compositeRequest": [
       {
           "method": "POST",
           "url": "/services/data/v52.0/sobjects/Account",
           "referenceId": "refAccount",
           "body": {
               "Name": "Rush"
           }
       },
       {
           "method": "POST",
           "url": "/services/data/v52.0/sobjects/Individual",
           "referenceId": "refIndividualGeddy",
           "body": {
               "LastName": "Lee",
               "Occupation": "Bass"
           }
       },
       {
           "method": "POST",
           "url": "/services/data/v52.0/sobjects/Contact",
           "referenceId": "refContactGeddy",
           "body": {
               "FirstName": "Geddy",
               "LastName": "Lee",
               "AccountId": "@{refAccount.id}",
               "IndividualId": "@{refIndividualGeddy.id}"
           }
       },
       {
           "method": "POST",
           "url": "/services/data/v52.0/sobjects/Individual",
           "referenceId": "refIndividualAlex",
           "body": {
               "LastName": "Lifeson",
               "Occupation": "Guitar"
           }
       },
       {
           "method": "POST",
           "url": "/services/data/v52.0/sobjects/Contact",
           "referenceId": "refContactAlex",
           "body": {
               "FirstName": "Alex",
               "LastName": "Lifeson",
               "AccountId": "@{refAccount.id}",
               "IndividualId": "@{refIndividualAlex.id}"
           }
       },
       {
           "method": "POST",
           "url": "/services/data/v52.0/sobjects/Individual",
           "referenceId": "refIndividualNeil",
           "body": {
               "LastName": "Peart",
               "Occupation": "Drums"
           }
       },
       {
           "method": "POST",
           "url": "/services/data/v52.0/sobjects/Contact",
           "referenceId": "refContactNeil",
           "body": {
               "FirstName": "Neil",
               "LastName": "Peart",
               "AccountId": "@{refAccount.id}",
               "IndividualId": "@{refIndividualNeil.id}"
           }
       }
   ]
}

In simple language, the requirements are translated as follows:

  1. Create a new account for Rush

  2. Create your own record for bass

  3. Create a contact for Geddy Lelle and Link a Rush account and individual bass information

  4. Create your own record for guitar

  5. Create a contact for Alex Lifeson and Link a Rush account and individual guitar records

  6. Create your own record for the drum

  7. Create a contact for Neil Peart and Link a Rush account and individual drum records

The request used the following POST URI:

{{_endpoint}}/services/data/v{{version}}/composite

After we submit the request, we get an HTTP status of 200 (OK):

The resulting payload is included below:

{
   "compositeResponse": [
       {
           "body": {
               "id": "0015e00000JcTSMAA3",
               "success": true,
               "errors": []
           },
           "httpHeaders": {
               "Location": "/services/data/v52.0/sobjects/Account/0015e00000JcTSMAA3"
           },
           "httpStatusCode": 201,
           "referenceId": "refAccount"
       },
       {
           "body": {
               "id": "0PK5e000000sYlKGAU",
               "success": true,
               "errors": []
           },
           "httpHeaders": {
               "Location": "/services/data/v52.0/sobjects/Individual/0PK5e000000sYlKGAU"
           },
           "httpStatusCode": 201,
           "referenceId": "refIndividualGeddy"
       },
       {
           "body": {
               "id": "0035e00000FMahHAAT",
               "success": true,
               "errors": []
           },
           "httpHeaders": {
               "Location": "/services/data/v52.0/sobjects/Contact/0035e00000FMahHAAT"
           },
           "httpStatusCode": 201,
           "referenceId": "refContactGeddy"
       },
       {
           "body": {
               "id": "0PK5e000000sYlPGAU",
               "success": true,
               "errors": []
           },
           "httpHeaders": {
               "Location": "/services/data/v52.0/sobjects/Individual/0PK5e000000sYlPGAU"
           },
           "httpStatusCode": 201,
           "referenceId": "refIndividualAlex"
       },
       {
           "body": {
               "id": "0035e00000FMahMAAT",
               "success": true,
               "errors": []
           },
           "httpHeaders": {
               "Location": "/services/data/v52.0/sobjects/Contact/0035e00000FMahMAAT"
           },
           "httpStatusCode": 201,
           "referenceId": "refContactAlex"
       },
       {
           "body": {
               "id": "0PK5e000000sYlQGAU",
               "success": true,
               "errors": []
           },
           "httpHeaders": {
               "Location": "/services/data/v52.0/sobjects/Individual/0PK5e000000sYlQGAU"
           },
           "httpStatusCode": 201,
           "referenceId": "refIndividualNeil"
       },
       {
           "body": {
               "id": "0035e00000FMahNAAT",
               "success": true,
               "errors": []
           },
           "httpHeaders": {
               "Location": "/services/data/v52.0/sobjects/Contact/0035e00000FMahNAAT"
           },
           "httpStatusCode": 201,
           "referenceId": "refContactNeil"
       }
   ]
}

Notice how it exists httpStatusCode for each sub-request. This allows the feature or service developer to understand which parts of the request were successful and which were unsuccessful. In fact, there are even allOrNone property which controls the recovery of the event – allowing successful items to be retained or all to be discarded.

In the example above, I made one API call to Salesforce instead of seven. This reflects an 85% improvement. This benefit can be further assessed by avoiding opportunities cyclomatic complexity problems that may arise after making the request and waiting for a response before proceeding with the next request for relevant data.

Conclusion

Since 2021, I have been trying to live up to the following mission pledge that I think I can apply to any IT professional:

“Focus your time on providing features / functions that add value to your intellectual property. Take advantage of the framework, products and services for everything else. “

– J. Vester

In this article, we were able to explore the concept of combination requests against a robust Salesforce API. Although there is a small learning curve in understanding the approach, the use of concatenated requests not only compresses all relevant items into a single request, but reduces API requests by n + 1, which is counted in the constraints of the Salesforce ecosystem.

Certainly, Salesforce has implemented a service that allows developers of features and service levels to combine related information into a single request, avoiding the additional programming logic required to make the first request and also waiting for a response before submitting the next request.

If your scenario does not exceed 25 sub-requests, you should consider using pooled requests when connecting to the Salesforce API. In fact, API developers outside the Salesforce realm should consider learning from the Salesforce team and offering combination requests as a viable option.

Do you see I ended up learning something new about the Salesforce API just by exploring the idea of ​​combo requests. It seems to happen every time.

Very awesome day!

.

LEAVE A REPLY

Please enter your comment!
Please enter your name here