,

Salesforce Graph API

swagataray Avatar

Salesforce Graph API aka Salesforce Composite Graph API is a part of the bigger API umbrella called Salesforce composite Graph API. This Graph API is very powerful API which can be utilized for API aggregation, orchestration etc. I will discuss these further but if you want to learn about Composite API, then click here

Salesforce URL to initiate Graph API

/services/data/vXX.X/composite/graph

Let me directly jump into the use cases

Business Scenario 1

You have an ecommerce site which is connected to Salesforce (Your CRM). If customer logs in to your Ecommerce site, then you need to show the customer’s details (Person Account) and all the related Phone numbers of that Account by using an external ID (External_Member__c). Below is the ERD for the understanding.

URL and Method

services/data/v58.0/composite (POST)

Request Payload for Salesforce Graph API

        {
            "compositeRequest": [
                {
                    "url": "/services/data/v57.0/query?q=select+id%2CFirstName%2C+LastName+from+Account+where+External_Member__c+%3D%2723333%27",
                    "method": "GET",
                    "referenceId": "accountId"
                }
                ,
                {
                   "url": "/services/data/v57.0/query?q=select+id%2Cname%2CIsPrimary+from+ContactPointPhone+where+ParentId+%3D+%27@{accountId.records[0].Id}%27",
                    "method": "GET",
                    "referenceId": "contactPointPhoneRef"
                }

            ]

        }

Salesforce Graph API Response

{
    "compositeResponse": [
        {
            "body": {
                "totalSize": 1,
                "done": true,
                "records": [
                    {
                        "attributes": {
                            "type": "Account",
                            "url": "/services/data/v57.0/sobjects/Account/0017798812ImUJMAA3"
                        },
                        "Id": "0017700000ImUJMAA3",
                        "FirstName": "Swagata",
                        "LastName": "Ray"
                    }
                ]
            },
            "httpHeaders": {},
            "httpStatusCode": 200,
            "referenceId": "accountId"
        },
        {
            "body": {
                "totalSize": 2,
                "done": true,
                "records": [
                    {
                        "attributes": {
                            "type": "ContactPointPhone",
                            "url": "/services/data/v57.0/sobjects/ContactPointPhone/0Ow7704441GokrCAC"
                        },
                        "Id": "0Ow77009999GokrCAC",
                        "Name": "1234566788",
                        "IsPrimary": false
                    },
                    {
                        "attributes": {
                            "type": "ContactPointPhone",
                            "url": "/services/data/v57.0/sobjects/ContactPointPhone/0Ow77089870GoksCAC"
                        },
                        "Id": "0Ow77158800GoksCAC",
                        "Name": "1234566789",
                        "IsPrimary": true
                    }
                ]
            },
            "httpHeaders": {},
            "httpStatusCode": 200,
            "referenceId": "contactPointPhoneRef"
        }
    ]
}

Explanation

This Composite API call encapsulates two internal GET call by treating them as one. Moreover, I am passing the result from the first GET request to the second by using @{accountId.records[0].Id}. Here, accountId = referenceId andrecords = resultSet from the previous GET call.
The beauty of this approach is that instead of using two REST callouts and APEX and other logic to implement, this is only ONE Graph API callout and it handles everything. This is an excellent way to do the aggregation at the API level

Business Scenario 2

You have application which sends the Member information (Person Account , Contact Point Email ) and it’s Member’s consent to use the Email (Contact Point Consent) in a batch of 60 Member records at a time. So, you need proper orchestration to add those Data into correct objects with proper relationship intact. Composite Graph API is your best friend. Let’s see, how we can manage this using Graph API. To understand the ERD between objects, look into previous ERD which is mentioned in the Business Scenario 1.

URL and Method

services/data/v58.0/composite/graph (POST)

Request Payload

{   "allOrNone": true,
    "graphs" : [
        {
            "graphId" : "1",
            "compositeRequest" : [
                {
                    "url" : "/services/data/v58.0/sobjects/Account/",
                    "body" : {
                         "FirstName" : "Swagata",
                         "LastName" : "Ray",
                         "RecordTypeId" :"0128V000221dwad",                        
                         "PersonBirthdate" : "1977-11-22",
                         "PersonGender" : "Male",
                         "PersonPronouns": "He/Him",
                         "External_Member__c" :"ABC9912"
                    },
                    "method" : "POST",
                    "referenceId" : "reference_id_account_1"
                },
               
                {
                    "url" : "/services/data/v58.0/sobjects/ContactPointEmail/",
                    "body" : {
                        "EmailAddress" : "test@test.com",                        
                        "UsageType" :"Home",
                        "IsPrimary" : "true",                        
                        "ParentId" : "@{reference_id_account_1.id}"
                    },
                    "method" : "POST",
                    "referenceId" : "reference_id_CPE_1"
                },
                
                {
                    "url" : "/services/data/v58.0/sobjects/ContactPointConsent/",
                    "body" : {
                        "name" : "Swagata - Eligibility Consent - Phone",
                        "PrivacyConsentStatus" : "OptIn" ,
                        "ContactPointId" : "@{reference_id_CPE_1.id}"
                    },
                    "method" : "POST",
                    "referenceId" : "reference_CPC_1"
                }
            ]
        }
        ,
        {
            "graphId" : "2",
            "compositeRequest" : [
                {
                    "url" : "/services/data/v58.0/sobjects/Account/",
                    "body" : {
                         "FirstName" : "Sibu",
                         "LastName" : "Banf",
                         "RecordTypeId" :"0128V000221dwad",                        
                         "PersonBirthdate" : "1945-11-22",
                         "PersonGender" : "Male",
                         "PersonPronouns": "He/Him",
                         "External_Member__c" :"ABC9988"
                    },
                    "method" : "POST",
                    "referenceId" : "reference_id_account_2"
                },
               
                {
                    "url" : "/services/data/v58.0/sobjects/ContactPointEmail/",
                    "body" : {
                        "EmailAddress" : "testsample@test.com",                        
                        "UsageType" :"Home",
                        "IsPrimary" : "true",                        
                        "ParentId" : "@{reference_id_account_2.id}"
                    },
                    "method" : "POST",
                    "referenceId" : "reference_id_CPE_2"
                },
                
                {
                    "url" : "/services/data/v58.0/sobjects/ContactPointConsent/",
                    "body" : {
                        "name" : "Sibu - Eligibility Consent - Phone",
                        "PrivacyConsentStatus" : "OptIn" ,
                        "ContactPointId" : "@{reference_id_CPE_2.id}"
                    },
                    "method" : "POST",
                    "referenceId" : "reference_CPC_2"
                }
            
			]
		}
    ]
}

Response

{
    "graphs": [
        {
            "graphId": "1", 
            "graphResponse": {
                "compositeResponse": [
                    {
                        "body": {
                            "id": "0017700000KbOQkAAN",
                            "success": true,
                            "errors": []
                        },
                        "httpHeaders": {
                            "Location": "/services/data/v58.0/sobjects/Account/0017700000KbOQkAAN"
                        },
                        "httpStatusCode": 201,
                        "referenceId": "reference_id_account_1"
                    },
                    {
                        "body": {
                            "id": "9Vl77000000GywGCAS",
                            "success": true,
                            "errors": []
                        },
                        "httpHeaders": {
                            "Location": "/services/data/v58.0/sobjects/ContactPointEmail/9Vl77000000GywGCAS"
                        },
                        "httpStatusCode": 201,
                        "referenceId": "reference_id_CPE_1"
                    },
                    {
                        "body": {
                            "id": "0ZX77000000CknyGAC",
                            "success": true,
                            "errors": []
                        },
                        "httpHeaders": {
                            "Location": "/services/data/v58.0/sobjects/ContactPointConsent/0ZX77000000CknyGAC"
                        },
                        "httpStatusCode": 201,
                        "referenceId": "reference_CPC_1"
                    }
                ]
            },
            "isSuccessful": true
        },
        {
            "graphId": "2", 
            "graphResponse": {
                "compositeResponse": [
                    {
                        "body": {
                            "id": "0017700000KbOQlAAN",
                            "success": true,
                            "errors": []
                        },
                        "httpHeaders": {
                            "Location": "/services/data/v58.0/sobjects/Account/0017700000KbOQlAAN"
                        },
                        "httpStatusCode": 201,
                        "referenceId": "reference_id_account_2"
                    },
                    {
                        "body": {
                            "id": "9Vl77000000GywHCAS",
                            "success": true,
                            "errors": []
                        },
                        "httpHeaders": {
                            "Location": "/services/data/v58.0/sobjects/ContactPointEmail/9Vl77000000GywHCAS"
                        },
                        "httpStatusCode": 201,
                        "referenceId": "reference_id_CPE_2"
                    },
                    {
                        "body": {
                            "id": "0ZX77000000CknzGAC",
                            "success": true,
                            "errors": []
                        },
                        "httpHeaders": {
                            "Location": "/services/data/v58.0/sobjects/ContactPointConsent/0ZX77000000CknzGAC"
                        },
                        "httpStatusCode": 201,
                        "referenceId": "reference_CPC_2"
                    }
                ]
            },
            "isSuccessful": true
        }
    ]
}

Explanation

The beauty of the Salesforce Graph API is in it’s simple implementation structure. In this scenario, I basically inserted records to three different objects with correct relationship intact and that too using bulk mode which would take at least three separate REST API calls and some some logic. Furthermore, “allOrNone” parameter can be used to make sure either all the transactions is successful or not. By default “allOrNone” is true. A points to remember that “allOrNone” works in the graph level. So, it is quite possible that one Graph can be successful and other can be errored out. Another thing to remember is that Subrequests in one graph can’t reference subrequests from another graph.

Node and Depth

In the Salesforce Graph API world each subrequests is represented by a node. Addition to that, each reference pointing to another node is represented as a depth. So in the above graph API request payload has two graphs (graphId) and each graph is comprise with 3 nodes with 3 depths. However, one Payload can have maximum 500 nodes and can reaches to 15 depth.

Business Scenario 3

You need to create a task for a Person Account (Member) so that your sales representative can reach out to your member for cross sell/ Up sell. So you will find a customer using external ID (External_Member__c) and then create a task and add that task to the member.

Salesforce Graph API Request Payload

{
    "graphs": [
        {
            "graphId": "1",
            "compositeRequest": [
              
                {
                    "url": "/services/data/v58.0/sobjects/Account/External_Member__c/889912",
                    "method": "GET",
                    "referenceId": "AccountResponse"
                },
                {
                    "url": "/services/data/v57.0/sobjects/Task",
                    "method": "POST",
                    "body": {
                        "Subject": "Call",
                        "whatId": "@{AccountResponse.Id}", 
                        "Status": "Open"                       
                    },
                    "referenceId": "TaskRef"
                }
            ]
        }
    ]
}

Response

{
    "graphs": [
        {
            "graphId": "1",
            "graphResponse": {
                "compositeResponse": [
                    {
                        "body": {
                            "attributes": {
                                "type": "Account",
                                "url": "/services/data/v58.0/sobjects/Account/0017700000J46HlAAJ"
                            },
                            "Id": "001770088546HlAAJ",
                            "IsDeleted": false,
                            "MasterRecordId": null,
                            "Name": "Swagata Ray",
                            "LastName": "Ray",
                            "FirstName": "Swagata",
                            "Salutation": null,
                            "MiddleName": null,
                            "Suffix": null,
                            "Type": null,
                            "RecordTypeId": "0128V0000010DtWQAU",
                            
                        },
                        "httpHeaders": {
                            "ETag": "\"gTI7lF2oYMlDxM+gTW1a62nzqxfxxihRqAygUNh9DPs=\"",
                            "Last-Modified": "Tue, 12 Sep 2023 14:30:26 GMT"
                        },
                        "httpStatusCode": 200,
                        "referenceId": "AccountResponse"
                    },
                    {
                        "body": {
                            "id": "00T7700000h1mQPEAY",
                            "success": true,
                            "errors": []
                        },
                        "httpHeaders": {
                            "Location": "/services/data/v57.0/sobjects/Task/00T7788890h1mQPEAY"
                        },
                        "httpStatusCode": 201,
                        "referenceId": "TaskRef"
                    }
                ]
            },
            "isSuccessful": true
        }
    ]
}

Limitation of the Graph API

  • Maximum number of graphs in one payload is 75
  • You can go up to 15 depth. This means that it will cover almost all complex structure and need.
  • Maximum nodes can be 500. One subsequent request is one node.

Reference

Blog on the Composite Tree API

Graph API developer guide

swagataray Avatar

2 responses to “Salesforce Graph API”

  1. […] Blog on the Composite Graph API […]

  2. […] The Salesforce Composite Graph API enables the execution of multiple operations within a single request via a unified interface. This feature enables programmers to condense numerous REST API requests, such as CRUD operations, queries, and custom actions, into a solitary transaction. […]

Leave a Reply

Related articles

Discover more from Tech Talk

Subscribe now to keep reading and get access to the full archive.

Continue reading