Salesforce Development: Integrations

Salesforce Developer Tutorial: How to use Wrapper Classes in Apex to Simplify your Integrations

4 min read

Subscribe on YouTube

Why This Is Useful

You’re calling an external API. It sends you back a big pile of JSON. Now what?

You could untangle it by hand with JSON.deserializeUntyped() and a forest of casts, ending up with code full of (Map<String, Object>) data.get('thing') that nobody, including you, can read a month later.

Or you could use a wrapper class: an Apex class shaped like the JSON, so Apex can deserialize straight into proper typed objects. Then you get autocomplete, compile time checking, and code that reads like code.

Wrapper classes also work brilliantly for bundling data to send to a Lightning Web Component, which we’ll get to.


The Code

All of this is up on GitHub if you’d rather just read it there.

Here’s a wrapper for Reddit’s API response:

Apex
public class Salesforce_Reddit
{
    @AuraEnabled
    public Post data;

    public class Post
    {
        @AuraEnabled
        public List<Children> children;
    }

    public class Data
    {
        @AuraEnabled
        public String author;
        @AuraEnabled
        public String title;
        @AuraEnabled
        public String url;
    }

    public class Children
    {
        public Data data;
    }

    public static Salesforce_Reddit parse(String json)
    {
        return (Salesforce_Reddit) System.JSON.deserialize(json, Salesforce_Reddit.class);
    }
}

Notice the shape. The JSON has a data object containing a children array, each with its own data object holding author, title and url. The class mirrors that exactly, with inner classes for each nested level.

That’s the whole trick: your class structure has to match the JSON structure, and your property names have to match the JSON keys. Get those right and deserialization just works.


Using It

Apex
public class Reddit_Post_Retriever
{
    public List<Salesforce_Reddit.Data> getPosts()
    {
        HttpRequest req = new HttpRequest();
        req.setEndpoint('callout:Reddit/r/salesforce/hot.json');
        req.setMethod('GET');

        HttpResponse res = new Http().send(req);

        Salesforce_Reddit reddit = Salesforce_Reddit.parse(res.getBody());

        List<Salesforce_Reddit.Data> posts = new List<Salesforce_Reddit.Data>();
        for (Salesforce_Reddit.Children child : reddit.data.children)
        {
            posts.add(child.data);
        }
        return posts;
    }
}

Look at reddit.data.children. Typed, autocompleted, and if you typo it the compiler stops you. Compare that to digging through nested untyped Maps and hoping.


Don’t Write These By Hand

Genuinely, don’t. Building a wrapper for a big API response by hand is tedious and easy to get subtly wrong.

Use JSON2Apex. Paste in a sample response, it generates the class. That comment at the top of the file above? That’s exactly what generated it.

Then clean up what it gives you, because it tends to be a bit verbose and the naming can be rough. But it does the structural work, which is the boring bit.


When JSON Keys Are Reserved Words

You’ll hit this eventually. The API sends a key called class or date or currency, and Apex won’t let you name a variable that.

The fix is to name the property something legal and remap it:

Apex
public class MyWrapper
{
    public String className;   //JSON key is actually "class"

    public static MyWrapper parse(String json)
    {
        //Swap the reserved word out before deserializing
        json = json.replace('"class"', '"className"');
        return (MyWrapper) System.JSON.deserialize(json, MyWrapper.class);
    }
}

Slightly grubby, universally used, and JSON2Apex does this for you automatically when it spots one.


What Those @AuraEnabled Annotations Are For

They’re not needed for deserialization at all. They’re there so this wrapper can be handed straight to a Lightning Web Component.

Any property you want visible in an LWC needs @AuraEnabled. Miss one and it silently arrives as undefined in your JavaScript, which is a fun thirty minutes of debugging.

This is the second big use for wrapper classes: bundling exactly the data your component needs into one tidy object, rather than making the component do six separate calls and stitch things together itself.

Apex
public class AccountSummary
{
    @AuraEnabled public Account acct;
    @AuraEnabled public List<Contact> contacts;
    @AuraEnabled public Decimal totalOpportunityValue;
    @AuraEnabled public Boolean isHighValue;
}

One Apex call, one object, and your component gets exactly what it needs in the shape it wants it. Much nicer than three wire adapters and some assembly.


Going The Other Way

Wrappers work just as well for building JSON to send out:

Apex
public class AccountWrapper
{
    public Account acct;
}

//Then...
AccountWrapper wrapper = new AccountWrapper();
wrapper.acct = myAccount;

String jsonToSend = JSON.serialize(wrapper);

Which is exactly what we do in the post on sending POST requests in Apex, and it’s a lot safer than building JSON with string concatenation.


A Few Gotchas

Property names are case sensitive. Title won’t catch a JSON key of title.

Missing keys are fine. If the JSON doesn’t contain something your class declares, it just ends up null. Handy, but it means a typo fails silently.

Extra keys are fine too, as long as you use JSON.deserialize(). Use deserializeStrict() and unexpected keys throw an exception, which is useful when you want to know the API changed shape.

Full details in the JSON support documentation.


Get Coding With The Force Merch!!

We now have a redbubble store setup so you can buy cool Coding With The Force merchandise! Please check it out! Every purchase goes to supporting the blog and YouTube channel.

Get Shirts Here!
Get Cups, Artwork, Coffee Cups, Bags, Masks and more here!


Check Out More Coding With The Force Stuff!

If you liked this post make sure to follow us on all our social media outlets to stay as up to date as possible with everything!

Youtube
Patreon
Github
Facebook
Twitter
Instagram


Salesforce Development Books I Recommend

Advanced Apex Programming
Salesforce Lightning Platform Enterprise Architecture
Mastering Salesforce DevOps

Good Non-SF Specific Development Books:

Clean Code
Clean Architecture