Creating Child Objects Using Apex REST API

Hello, and welcome to Another Salesforce Blog! Here I will be posting solutions to problems that I couldn’t find an answer to in hopes of helping those who find themselves stuck when using the Salesforce platform.

User Story

We have an external application that collects Account and Contact information. The application sends information in JSON format. Previously, our sales team input this information manually. Let’s automate the process!

Background

The Apex REST API allows us to expose our Apex classes and methods to external applications via REST architecture. The Salesforce REST API Developer Guide can be found here. We will also be using JSON, which is described by Salesforce here.

Solution

Step One – Examine the JSON.

First, let’s take a look at the JSON that we’ll be playing around with. Salesforce gives a super basic example of a JSON output:

[
   {
      "Name" : "Xytrex Co.",
      "Description" : "Industrial Cleaning Supply Company",
      "Account Number" : "ABC15797531"
   },
   {
      "Name" : "Watson and Powell, Inc.",
      "Description" : "Law firm. New York Headquarters",
      "Account Number" : "ABC24689753"     
   }
]

We are going to customize this for our needs and add a couple of contacts:

   {
      "Name" : "Another Salesforce Blog",
      "Description" : "Evelyn's Blog!",
      "Account Number" : "ABC56418415",
      "contacts": [
          {
            "lastname": "Grizzle",
            "firstname": "Evelyn"
          },
          {
            "lastname": "Grizzle",
            "firstname": "Boudin"
          }
      ]
   }

This is similar to an output we may receive from a web app that collects prospect information. You’ll note that there are two levels of name/value pairs, one for the Account object, notated by curly brackets, and one for the array of Contact objects, notated by square brackets.

Step two – Expose Apex to REST Services.

Now that we’ve taken a look at what we’re dealing with, we need to write an Apex class.

The first thing that we have to do is annotate the class as a @RestResource. This will allow us to expose our Apex class as a REST Resource. In order to do this, our Apex class must be defined as global, and our urlMapping is relative to https://instance.salesforce.com/services/apexrest/. We want to manage the Account object, so we’ll call our class AccountManager.

@RestResource(urlMapping='/Account/AccountManager')
global with sharing class AccountManager {...}

Step three – Create Wrapper Classes.

Because we have two levels of name/value pairs, we’ll need to write two wrapper classes. All this means is that we will make two classes that contain collections of objects. We will need a corresponding object for each field listed in our JSON, and the spelling must match exactly. To represent our “contacts”, we will instantiate a list of contactParameters wrappers.

@RestResource(urlMapping='/Account/AccountManager')
global with sharing class AccountManager {
    global class accountParameters{
        global String Name;
        global String Description;
        global String Account_Number;
        global List<contactParameters> contacts;
    }

    global class contactParameters{
        global String lastname;
        global String firstname;
    }
}

Each of the objects instantiated in our wrapper classes will correspond to a field on the Account or Contact object.

Step four – Create HTTP POST Method.

After we have created our wrapper classes, the fun begins! We are going to create our HTTP POST method. A crash course in creating REST callouts can be found on Trailhead.

Table describing HTTP Methods via Trailhead

We want to create accounts and contacts, or “post” them to the server, so we will be utilizing the HTTP POST method. To designate our method as a POST method, we will use the @HttpPost annotation at the beginning of our class. We also need to utilize the RestContext class to access the RestRequest and RestResponse objects.

...
    @HttpPost
    global static List<String> createAccounts() {
        
        //rest context objects for request and response
        RestRequest req = RestContext.request;
...

Next, we’ll instantiate our accountParameters wrapper class and deserialize the JSON input into an instance of the accountParameters class.

...
        //wrapper for accepting parameters passed in and deserialize parameters into wrapper
        accountParameters parameters = (accountParameters)JSON.deserialize(req.requestBody.toString(), accountParameters.Class);
...

After that, we’ll declare some objects that we need…

...
        //create Account list to store newly created Accounts
        List<Account> acctList = new List<Account>();
        
        //create String list to store response data
        List<String> returnResponse = new List<String>();
        
        //instantiate new Account object
        Account acctToInsert = new Account();
        
        //instantiate list of Contacts to insert
        List<Contact> contacts = new List<Contact>();
...

…populate our new Account object with values from our wrapper class and save it to the database…

...
        //populate values on acctToInsert from deserialized parameters
        acctToInsert.Name = parameters.Name;
        acctToInsert.Description = parameters.Description;
        acctToInsert.AccountNumber = parameters.Account_Number;
        
        //save Account to database
        Database.SaveResult sr = Database.Insert(acctToInsert);
        
        //populate returnRepsonse with response information
        if(sr.isSuccess()){
	        returnResponse.add('Success! Account ID ' + sr.getId() + ' created.');
        }
        else{
            returnResponse.add('Error: ' + sr.getErrors());
        }
...

…and iterate through the Contact children in our contacts list that we defined in our wrapper class.

...
        //iterate through Contact children to insert Contacts
        if(!parameters.contacts.isEmpty()){
            for(contactParameters CP : parameters.contacts){
                Contact con = new Contact();
                con.LastName = CP.lastname;
                con.FirstName = CP.firstname;
                con.AccountId = acctToInsert.Id;
                
                contacts.add(con);
            }
        }
        
        //save Contacts to database
        Database.SaveResult[] srList = Database.Insert(contacts, false);
        
        //populate returnRepsonse with response information
        for(Database.SaveResult save : srList){
            if(save.isSuccess()){
                returnResponse.add('Success! Contact ID ' + save.getId() + ' created.');
            }
            else{
                returnResponse.add('Error: ' + save.getErrors());
            }
        }
        return returnResponse;
    }
...

All in all, our code will look like this:

@RestResource(urlMapping='/Account/AccountManager')
global with sharing class AccountManager {

    @HttpPost
    global static List<String> createAccount(){
        //rest context objects for request and response
        RestRequest req = RestContext.request;
                
        //wrapper for accepting parameters passed in and deserialize parameters into wrapper
        accountParameters parameters = (accountParameters)JSON.deserialize(req.requestBody.toString(), accountParameters.Class);
        
        //create Account list to store newly created Accounts
        List<Account> acctList = new List<Account>();
        
        //create String list to store response data
        List<String> returnResponse = new List<String>();
        
        //instantiate new Account object
        Account acctToInsert = new Account();
        
        //instantiate list of Contacts to insert
        List<Contact> contacts = new List<Contact>();
        
        //populate values on acctToInsert from deserialized parameters
        acctToInsert.Name = parameters.Name;
        acctToInsert.Description = parameters.Description;
        acctToInsert.AccountNumber = parameters.Account_Number;
        
        //save Account to database
        Database.SaveResult sr = Database.Insert(acctToInsert);
        
        //populate returnRepsonse with response information
        if(sr.isSuccess()){
	        returnResponse.add('Success! Account ID ' + sr.getId() + ' created.');
        }
        else{
            returnResponse.add('Error: ' + sr.getErrors());
        }
        
        //iterate through Contact children to insert Contacts
        if(!parameters.contacts.isEmpty()){
            for(contactParameters CP : parameters.contacts){
                Contact con = new Contact();
                con.LastName = CP.lastname;
                con.FirstName = CP.firstname;
                con.AccountId = acctToInsert.Id;
                
                contacts.add(con);
            }
        }
        
        //save Contacts to database
        Database.SaveResult[] srList = Database.Insert(contacts, false);
        
        //populate returnRepsonse with response information
        for(Database.SaveResult save : srList){
            if(save.isSuccess()){
                returnResponse.add('Success! Contact ID ' + save.getId() + ' created.');
            }
            else{
                returnResponse.add('Error: ' + save.getErrors());
            }
        }
        return returnResponse;
    }

    global class accountParameters{
        global String Name;
        global String Description;
        global String Account_Number;
        global List<contactParameters> contacts;
    }

    global class contactParameters{
        global String lastname;
        global String firstname;
    }
}

Step five – Test POST Method in Workbench REST Explorer.

Now for the fun part!

We select POST, populate our URI with '/services/apexrest/Account/AccountManager', paste in our JSON, and hit execute!

Success! Our records were created!

Step six – Write a Test Method.

Lastly, we need to write our test method. Because our POST method returns a list of strings declaring success or error, this is fairly simple.

@isTest
global with sharing class AccountManagerTest {

    @isTest static void testCreate() {
        RestRequest request = new RestRequest();
        RestResponse response = new RestResponse();
        
        request.requestURI = '/services/apexrest/Account/';
        request.httpMethod = 'POST';
        
        String reqBody = '{"Name":"TESTACCOUNT","Description":"TESTING","AccountNumber":"ABC12345","contacts":[{"lastname":"TEST","firstname":"ONE"},{"lastname":"TEST","firstname":"TWO"}]}';
        
        request.requestBody = Blob.valueof(reqBody);        
        
        RestContext.request = request;
        RestContext.response = response;
        
        List<String> createResults = AccountManager.createAccount();
        system.assert(createResults.contains('Success'));
    }
}

Line by line, we:

  • create a new REST Request and Response
  • define our requestURI and HttpMethod
  • define a String with a test payload
  • set the test payload as the requestBody
  • define the RestContext
  • call the CreateAccount method in our AccountManager class
  • check to see if our returned string contains ‘Success’
  • that’s it!

Thanks for reading, let me know if you have any comments or questions!

-Evelyn, Another Salesforce Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: