To understand how you should structure response data from the Apex controller, let's take an example of Apex code that is needed to display a list of accounts for a Lightning Component:
public class AccountController{
@AuraEnabled
public Static List<AccountWrapper> queryAllAccounts(){
List<AccountWrapper> accountWrapperList = New List<AccountWrapper>();
List<Account> myAccounts = [Select id, Name, BillingState.
(Select id
From Contacts)
From Account];
if(!myAccounts.isEmpty()){
for(Account currentAccount : myAccounts){
accountWrapperList.add(new AccountWrapper (..) );
}
}
return accountWrapperList;
}
}
This is the message/wrapper class code:
public class AccountWrapper{
@AuraEnabled
Account currentAccount;
@AuraEnabled
Integer noOfContacts;
@AuraEnabled
Boolean isPartnerAccount;
@AuraEnabled
//Few more variables
public AccountWrapper(Account currentAccount, Integer noOfContacts, Boolean isPartnerAccount,..){
this.currentAccount = currentAccount;
....
}
}
Note that in this scenario the service is returning responses as a custom Apex type. It has been observed that using a JSON string as the response type improves the performance, compared to the return type of Apex that is custom-defined. The platform under the hood suffers from some performance issues, and this is more noticeable with large datasets.
Instead, we can return as the JSON, using the following code snippet:
public class AccountQueryController{
@AuraEnabled
public static String queryAllAccounts(){
List<AccountWrapper> accountWrapperList = New List<AccountWrapper>();
List<Account> myAccounts = [Select id, Name, BillingState.
(Select id
From Contacts)
From Account];
return JSON.serialize(myAccounts);
}
You can then parse the string response into a valid JavaScript object, using JSON.parse() on the JavaScript. It has been observed that the performance is significantly improved via this method.