Some notes about using the /composite API to do up to 25 statements in a single API call.
- Composite API resources
- https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_composite_composite.htm
- Technical video https://youtu.be/R6eVlc3Dwco?t=2416
- Full technical documentation https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/requests_composite.htm
- Notes about using the Composite API
- This is a new feature from Salesforce, and it saves a significant number of API calls into Salesforce.
- You can have up to 25 REST API statements in one API call.
- NOTE: The API code can not have any conditional statements in it - it’s just one block with all of the records you want to query / create or update structured as a block of JSON then sent over to Salesforce.
- So for example for multiple Order Line Items, you will loop through the list of Line Items in your PHP code for example, and produce the JSON that has the 2 (+) Invoice Line Item POST statements
- If any one of the items fails the whole lot will fail.
I am using this to do an integration between a Website and Salesforce. The client is an NFP and doesn't have budget to get a dev to to Custom Apex REST.
So, I read the docco and did a nice piece of pseudo code referencing all fields in Salesforce and matching it up with the fields in the Website, I thought it was going to work like a charm.
My pseudo code (yes, with all the errors in it)
path = "/services/data/42.0" // On Update of an existing Contact's details or creation of a new Contact //If SFContactID is blank { "method" : "PATCH", "url" : path + "/sobjects/Account/UniqueID__c/ABCEnterprisesNSW", //Company Name+(Billing Address State or Other State) with spaces stripped out then trimmed to 255 chars "referenceID" : "refNewAccount", "body" : { "Name" : "ABC Enterprises", //Company "BillingStreet" : "15 Smith Street", //Billing Address - Street "BillingCity" : "Smithville", //Billing Address - Suburb "BillingState" : "NSW", //Billing Address - State or Other State "BillingPostalCode" : "2656", //Billing Address - Postcode "BillingCountry" : "Australia", //Billing Address Country "Phone" : "02 9898 9898" //Business Phone } }, //Now get that Account ID just created or updated { "method" : "GET", "url" : path + "/sobjects/Account/@{refNewAccount.id}", "referenceId" : "refNewAccountInfo" }, // Now Create or Update the Contact { "method" : "PATCH", "url" : path + "/sobjects/Contact/UniqueID__c/JaneDoejdoe@gmail.com", //First Name + Surname + Email Address with spaces striped out then trimmed to 255 chars "referenceId" : "refNewContact", "body" : { "Saluation" : "Ms", //Title "FirstName" : "Jane", //First Name "LastName" : "Doe", //Surname "Title" : "Director", //Position "Email" : "jdoe@gmail.com", //Email Address "AccountId" : "@{NewAccountInfo.Id}", "MailingStreet" : "@{NewAccountInfo.BillingStreet}", "MailingCity" : "@{NewAccountInfo.BillingCity}", "MailingState" : "@{NewAccountInfo.BillingState}", "MailingPostalCode" : "@{NewAccountInfo.BillingPostalCode}", "MailingCountry" : "@{NewAccountInfo.BillingCountry}", "Phone" : "@{NewAccountInfo.Phone}", "MobilePhone" : "9908960940" //Mobile } }, //Now get that Contact ID just created or updated { "method" : "GET", "url" : path + "/sobjects/Contact/@{refNewContact.id}", "referenceId" : "refContactInfo" }, // Update that into your SFContactID field on the website
Project go ahead happens and the first thing I do is fix up my pseudo code to test it in Workbench. Oops, I got so much wrong - apart from the spelling mistakes like 'Saluation' rather than 'Salutation'.
Gotchas
- referenceId must be spelt referenceId, not referenceID
- Doing a PATCH on Account does not return the referenceId if it does not create a new Account. This seems weird to me, but I'm going to have to run with it for now.
- The refNewAccount.id will not work if the Account is updated, only if it is created.
"method" : "PATCH", "url" : "/services/data/v41.0/sobjects/Account/UniqueID__c/ABCEnterprisesVIC", "referenceId" : "refNewAccount", "body" : { "Name" : "ABC Enterprises", "BillingStreet" : "15 Smith Street", "BillingCity" : "Smithville", "BillingState" : "VIC", "BillingPostalCode" : "2656", "BillingCountry" : "Australia", "Phone" : "02 9898 9898", } }, { "method" : "PATCH", "url" : "/services/data/v41.0/sobjects/Contact/UniqueID__c/JaneDoejdoe@gmail.com", "referenceId" : "refNewContact", "body" : { "Salutation" : "Ms", "FirstName" : "Jane", "LastName" : "Doe", "Title" : "Director", "Email" : "jdoe@gmail.com", "AccountId" : "@{refNewAccount.id}" }
- Doing a GET on an id returns the whole object, not just the ID
- "method" : "GET",
"url" : "/services/data/v41.0/sobjects/Contact/@{refNewContact.id}",
"referenceId" : "refContactInfo"
- "method" : "GET",
Solution
- So you have to do a GET with a query in the middle of the two PATCH methods.
- AND you can't use {{@{refNewAccount.id}}} syntax, you have to use the extended query syntax.
- So this is what finally worked!
{ "compositeRequest" : [ { "method" : "PATCH", "url" : "/services/data/v41.0/sobjects/Account/UniqueID__c/ABCEnterprisesNSW", "referenceId" : "refNewAccount", "body" : { "Name" : "ABC Enterprises", "BillingStreet" : "15 Smith Street", "BillingCity" : "Smithville", "BillingState" : "NSW", "BillingPostalCode" : "2656", "BillingCountry" : "Australia", "Phone" : "02 9898 9898" } }, { "method" : "GET", "url" : "/services/data/v41.0/query/?q=select+id,name,Industry,BillingStreet,BillingCity,BillingState,BillingPostalCode,BillingCountry,Phone+from+Account+where+UniqueID__c='ABCEnterprisesNSW'", "referenceId" : "refNewAccountInfo" }, { "method" : "PATCH", "url" : "/services/data/v41.0/sobjects/Contact/UniqueID__c/JaneDoejdoe@gmail.com", "referenceId" : "refNewContact", "body" : { "Salutation" : "Ms", "FirstName" : "Jane", "LastName" : "Doe", "Title" : "Director", "Email" : "jdoe@gmail.com", "AccountId" : "@{refNewAccountInfo.records[0].Id}", "MailingStreet" : "@{refNewAccountInfo.records[0].BillingStreet}", "MailingCity" : "@{refNewAccountInfo.records[0].BillingCity}", "MailingState" : "@{refNewAccountInfo.records[0].BillingState}", "MailingPostalCode" : "@{refNewAccountInfo.records[0].BillingPostalCode}", "MailingCountry" : "@{refNewAccountInfo.records[0].BillingCountry}", "Phone" : "@{refNewAccountInfo.records[0].Phone}", "MobilePhone" : "9908960940" } }, { "method" : "GET", "url" : "/services/data/v41.0/query/?q=select+id+from+Contact+where+UniqueID__c='JaneDoejdoe@gmail.com'", "referenceId" : "refNewContactId" }] }