[SalesForce] Displaying JSON response data from a wrapper class onto a VF Page

I'm currently working on a small app, to allow to better understand RESTful Webservices and how to consume them. The app connects to a RESTful API, and I need to find a way to display the JSON response onto a VF page.

The JSON response is an array, which is deserialized into a List for a wrapper class. However, when I call the data from the VF page, it does absolutely nothing and no errors are displayed, despite having a re-render function.

Am I calling the data correctly? Or does it have to be populated into a Map?

Here is my code:

JSON Response Snippet

[
    {
        "territoryId": "999991",
        "territoryName": "999991-Test",
        "startDate": "2018-01-01T00:00:00Z",
        "endDate": "9999-12-31T00:00:00Z",
        "recordIndex": 1
    },
    {
        "territoryId": "139445",
        "territoryName": "ABILENE TX DIAB PC1 139445",
        "startDate": "2016-07-01T00:00:00Z",
        "endDate": "9999-12-31T00:00:00Z",
        "recordIndex": 2
    },
]

Call Out Class

public class HAPI_callOut {

    public HAPI_TerrByCount_wrapper wrapper {get; set;}

    public void deserialize() {

        HttpRequest request = new HttpRequest();

        request.setEndpoint('callout:HAPI_CallOut/territories-by-country/US');
        request.setMethod('GET');
        request.setTimeout(120000);

        Http service = new Http();
        HttpResponse response = service.send(request);

        List<HAPI_TerrByCount_wrapper> wrapper = (List<HAPI_TerrByCount_wrapper>)JSON.deserialize(response.getBody(), List<HAPI_TerrByCount_wrapper>.class);
    }
}

Wrapper Class

public class HAPI_TerrByCount_wrapper {

    public class TerritoriesByCountry {

        public String territoryId {get; set;}
        public String territoryName {get; set;}
        public String startDate {get; set;}
        public String endDate {get; set;}
        public Integer recordIndex {get; set;}
    }

    public List<TerritoriesByCountry> terrByCountList {get; set;}

}

Visualforce Page

    <apex:page controller="HAPI_callOut">
    <apex:form>
        <apex:pageBlock title="Alignment Territories By Country Data">
            <apex:pageBlockButtons>
                <apex:commandButton value="Get Data!" action="{!deserialize}" reRender="TerrByCountBlock"/>
            </apex:pageBlockButtons>
            <apex:pageBlockSection id="TerrByCountBlock" columns="1">
                <apex:repeat value="{!wrapper.terrByCountList}" var="territory">
                    <apex:pageBlockSection columns="3">
                        <apex:facet name="header"> Territory ID {!territory.territoryId}</apex:facet>
                        <apex:pageBlockSectionItem>
                            <apex:outputLabel value="Territory Name" for="territoryName" />
                            <apex:outputText value="{!territory.territoryName}" id="territoryName" />
                        </apex:pageBlockSectionItem>
                        <apex:pageBlockSectionItem>
                            <apex:outputLabel value="Start Date" for="startDate" />
                            <apex:outputText value="{!territory.startDate}" id="startDate" />
                        </apex:pageBlockSectionItem>
                        <apex:pageBlockSectionItem>
                            <apex:outputLabel value="End Date" for="endDate" />
                            <apex:outputText value="{!territory.endDate}" id="endDate" />
                        </apex:pageBlockSectionItem>
                    </apex:pageBlockSection>
                </apex:repeat>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>

Thank you!

Update

Callout Class

public class HAPI_callOut {

    public List<HAPI_TerrByCount_wrapper> wrapper {get; set;}

    public void deserialize() {

        HttpRequest request = new HttpRequest();

        request.setEndpoint('callout:HAPI_CallOut/territories-by-country/US');
        request.setMethod('GET');
        request.setTimeout(120000);

        Http service = new Http();
        HttpResponse response = service.send(request);

        wrapper = (HAPI_TerrByCount_wrapper)JSON.deserialize(response.getBody(), HAPI_TerrByCount_wrapper.class);
    }
}

Error: Illegal assignment from HAPI_TerrByCount_wrapper to List

Best Answer

You're shadowing your Visualforce-accessible wrapper property with a local variable declaration:

    List<HAPI_TerrByCount_wrapper> wrapper = (List<HAPI_TerrByCount_wrapper>)JSON.deserialize(response.getBody(), List<HAPI_TerrByCount_wrapper>.class);

You need to remove the declaration (List<HAPI_TerrByCount_wrapper>) from your deserialize() method, because the local variable goes out of scope at the end of the method, but your property's value is never set.

Additionally, you need to make sure the type of your instance variable and the type of your deserializing code are in sync with one another. This is a little confusing (and definitely tripped me up, if you review the edit history of this answer!) because you're trying to deserialize a single HAPI_TerrByCount_wrapper object that contains a List<HAPI_TerrByCount_wrapper.TerritoriesByCountry>. However, your JSON can't directly be deserialized into HAPI_TerrByCount_wrapper or List<HAPI_TerrByCount_wrapper>, because that type has another layer of property declaration in the form of its instance variable terrByCountList, which is not represented in the JSON.

What you'll need to do ultimately is deserialize a List<HAPI_TerrByCount_wrapper.TerritoriesByCountry> and assign that list to your wrapper.terrByCountList property.

This will prevent a "‘{‘ is expected, but the JSON response is starts with an array ‘[‘" error, because you're deserializing the correct type.

(I'm sorry for the confusion - I initially overlooked the fact that you had a wrapper class around the list that actually mapped to the JSON).