
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.

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!

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
andResponse
- define our
requestURI
andHttpMethod
- define a
String
with a test payload - set the test payload as the
requestBody
- define the
RestContext
- call the
CreateAccount
method in ourAccountManager
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

Make a one-time donation
Make a monthly donation
Make a yearly donation
Choose an amount
Or enter a custom amount
Help keep Another Salesforce Blog on the internet by donating today!
Your contribution is appreciated.
Your contribution is appreciated.
DonateDonate monthlyDonate yearly
3 responses to “Creating Child Objects Using Apex REST API”
Thank you very much! Explanation is so very clear.
LikeLike
very good post .i struggled a lot to find answer for this. Thank you
LikeLike
[…] It’s also super easy to serialize SObjects into JSON using a wrapper class, as we learned in Creating Child Objects Using Apex REST API, so let’s make a wrapper […]
LikeLike