Advanced 25 min read

Returning Data to LWC: Wrapper Classes and DTOs

By the end of this lesson, you'll be able to:

  • Return a custom wrapper class from an @AuraEnabled method
  • Explain why a DTO shape sometimes fits better than returning a raw sObject
  • Apply Module 16's wrapper class pattern to the LWC boundary specifically

Prerequisites: "Imperative Calls vs the Wire Service (the Apex Side)"

Returning a raw sObject: the simple case

@AuraEnabled
public static List<Account> getAccounts() {
    return [SELECT Id, Name, Industry FROM Account];
}
  1. @AuraEnabled — marks the method.
  2. public static List<Account> getAccounts() { — for a component that just needs to display real Account fields directly.
  3. return [SELECT Id, Name, Industry FROM Account]; — returning the queried sObject List is simple and works fine — exactly like every SOQL example since Module 20.
  4. } — closes the method.

When a wrapper class fits better

public class AccountSummary {
    @AuraEnabled public String name;
    @AuraEnabled public Integer openOpportunityCount;
    @AuraEnabled public Decimal totalWonRevenue;
}

@AuraEnabled
public static List<AccountSummary> getAccountSummaries() {
    List<AccountSummary> summaries = new List<AccountSummary>();

    for (Account acc : [SELECT Id, Name, Total_Won_Revenue__c, (SELECT Id FROM Opportunities WHERE IsClosed = false) FROM Account]) {
        AccountSummary summary = new AccountSummary();
        summary.name = acc.Name;
        summary.openOpportunityCount = acc.Opportunities.size();
        summary.totalWonRevenue = acc.Total_Won_Revenue__c;
        summaries.add(summary);
    }

    return summaries;
}
  1. public class AccountSummary { — this is Module 16's wrapper-class pattern, applied at the LWC boundary.
  2. @AuraEnabled public String name; — a real field.
  3. @AuraEnabled public Integer openOpportunityCount; — a computed value.
  4. @AuraEnabled public Decimal totalWonRevenue; — a rollup (Module 26).
  5. } — closes the wrapper class.
  6. (blank line)
  7. @AuraEnabled — marks the method.
  8. public static List<AccountSummary> getAccountSummaries() { — returns the wrapper, not a raw sObject.
  9. List<AccountSummary> summaries = new List<AccountSummary>(); — collects the results.
  10. (blank line)
  11. for (Account acc : [SELECT Id, Name, Total_Won_Revenue__c, (SELECT Id FROM Opportunities WHERE IsClosed = false) FROM Account]) { — the child-relationship subquery, Module 20.
  12. AccountSummary summary = new AccountSummary(); — builds one wrapper per account.
  13. summary.name = acc.Name; — the real field.
  14. summary.openOpportunityCount = acc.Opportunities.size(); — the computed value, from the subquery.
  15. summary.totalWonRevenue = acc.Total_Won_Revenue__c; — the rollup.
  16. summaries.add(summary); — collects it.
  17. } — closes the loop.
  18. (blank line)
  19. return summaries; — hands back a shape no single query alone could return directly, tailored to exactly what a dashboard component needs to display.
  20. } — closes the method.

Every field the UI needs also gets @AuraEnabled

Notice @AuraEnabled appears on the fields of AccountSummary, not just the method — each field the UI needs to read must be individually exposed too, the same annotation-based exposure principle from Lesson 2, now applied one level deeper.

Exercise

Write a wrapper class ContactSummary with @AuraEnabled fields fullName and email, and a method returning a List<ContactSummary> built from queried Contacts.

Show hint

Remember @AuraEnabled on both the fields and the method.

Salesforce: ○ Not connected Connect
APEX

Execution Results

Run your code to see the result.

Returning Data to LWC: Wrapper Classes and DTOs Quiz

1. Why might a custom wrapper class fit better than a raw sObject for a method exposed to an LWC?

Log in to submit the quiz and save your score.

My Notes

Log in to keep private notes on this lesson.

Questions about this lesson

No questions yet — be the first to ask.

Log in to ask a question about this lesson.

Summary

An @AuraEnabled method doesn't have to return a raw sObject — a custom wrapper class (or DTO, "Data Transfer Object") often shapes the data more usefully for exactly what the UI needs to display.