Wrapper Class Patterns

What Was Actually Done

Patterns

Pattern 1: UI Selection Wrapper

When to use: You need additional UI-only state such as selection or error flags.

public class ContactSelectionWrapper {
    @AuraEnabled public Contact record { get; set; }
    @AuraEnabled public Boolean isSelected { get; set; }
    @AuraEnabled public Boolean hasError { get; set; }
    @AuraEnabled public String errorMessage { get; set; }

    public ContactSelectionWrapper(Contact record) {
        this.record = record;
        this.isSelected = false;
        this.hasError = false;
    }
}

Pattern 2: Aggregated Data Wrapper

When to use: You must present combined data from multiple objects or queries.

public class AccountSummaryWrapper {
    @AuraEnabled public Id accountId { get; set; }
    @AuraEnabled public String accountName { get; set; }
    @AuraEnabled public Integer contactCount { get; set; }
    @AuraEnabled public Decimal totalOpenAmount { get; set; }
}

Service constructing the wrapper:

public with sharing class AccountSummaryService {
    @AuraEnabled(cacheable=true)
    public static List<AccountSummaryWrapper> getAccountSummaries() {
        List<AccountSummaryWrapper> summaries = new List<AccountSummaryWrapper>();

        // Example pattern: one SOQL with aggregates per account
        for (AggregateResult ar : [
            SELECT AccountId accId,
                   COUNT(Id) contactCount
            FROM Contact
            WHERE AccountId != null
            GROUP BY AccountId
        ]) {
            AccountSummaryWrapper w = new AccountSummaryWrapper();
            w.accountId = (Id) ar.get('accId');
            w.contactCount = (Integer) ar.get('contactCount');
            // Additional queries or cached data to populate name and totals
            summaries.add(w);
        }
        return summaries;
    }
}

Pattern 3: Integration DTO Wrapper

When to use: You need strict control over serialized payloads for REST/SOAP integrations.

public class ContactSyncDTO {
    public String externalId;
    public String firstName;
    public String lastName;
    public String email;

    public static ContactSyncDTO fromContact(Contact c) {
        ContactSyncDTO dto = new ContactSyncDTO();
        dto.externalId = c.External_Id__c;
        dto.firstName = c.FirstName;
        dto.lastName = c.LastName;
        dto.email = c.Email;
        return dto;
    }
}

Usage:

List<ContactSyncDTO> payload = new List<ContactSyncDTO>();
for (Contact c : contacts) {
    payload.add(ContactSyncDTO.fromContact(c));
}
String body = JSON.serialize(payload);

To Validate