0

I am developing a sort of gateway API for an Ionic mobile-app, which has to talk to some online API that doesn't accept front-end calls.

One call returns a JSON object, with a "data"-array of JObjects. A response of the server looks like this (below JSON just shows one result, to give an idea of what the server's response looks like):

{
    "currentPage": 1,
    "numberOfPages": 1,
    "totalResults": 19,
    "data": [
        {
            "id": "BznahA",
            "name": "Anheuser-Busch InBev",
            "nameShortDisplay": "Anheuser-Busch InBev",
            "description": "Anheuser-Busch operates 12 breweries in the United States, 14 in China and one in the United Kingdom. Anheuser-Busch's operations and resources are focused on adding to life's enjoyment not only through the responsible consumption of beer by adults, but through theme park entertainment and packaging.  In the United States, the company holds a 48.5 percent share of U.S. beer sales. Worldwide, Anheuser-Busch's beer sales volume was 128.4 million barrels in 2007.  The St. Louis-based company's subsidiaries include one of the largest U.S. manufacturers of aluminum beverage containers and one of the world's largest recyclers of aluminum beverage cans. Anheuser-Busch also has interests in malt production, rice milling, real estate development, turf farming, metalized and paper label printing, bottle production and transportation services.",
            "website": "http://www.anheuser-busch.com/",
            "established": "1852",
            "isOrganic": "N",
            "images": {
                "icon": "https://brewerydb-images.s3.amazonaws.com/brewery/BznahA/upload_0FkKKl-icon.png",
                "medium": "https://brewerydb-images.s3.amazonaws.com/brewery/BznahA/upload_0FkKKl-medium.png",
                "large": "https://brewerydb-images.s3.amazonaws.com/brewery/BznahA/upload_0FkKKl-large.png",
                "squareMedium": "https://brewerydb-images.s3.amazonaws.com/brewery/BznahA/upload_0FkKKl-squareMedium.png",
                "squareLarge": "https://brewerydb-images.s3.amazonaws.com/brewery/BznahA/upload_0FkKKl-squareLarge.png"
            },
            "status": "verified",
            "statusDisplay": "Verified",
            "createDate": "2012-01-03 02:41:44",
            "updateDate": "2018-11-02 02:15:01",
            "isMassOwned": "Y",
            "isInBusiness": "Y",
            "isVerified": "N",
            "locations": [
                {
                    "id": "ZApGug",
                    "name": "Main Brewery",
                    "streetAddress": "One Busch Place",
                    "locality": "Saint Louis",
                    "region": "Missouri",
                    "postalCode": "63118",
                    "phone": "(314) 577-2626",
                    "website": "http://www.anheuser-busch.com/",
                    "latitude": 38.5985037,
                    "longitude": -90.2093428,
                    "isPrimary": "Y",
                    "inPlanning": "N",
                    "isClosed": "N",
                    "openToPublic": "Y",
                    "locationType": "macro",
                    "locationTypeDisplay": "Macro Brewery",
                    "countryIsoCode": "US",
                    "yearOpened": "1852",
                    "status": "verified",
                    "statusDisplay": "Verified",
                    "createDate": "2012-01-03 02:41:44",
                    "updateDate": "2018-11-02 02:14:56"

Now, my gateway API processes this into self-made objects and returns it to the mobile app. The methods are defined as such:

var resp = await _clientFactory.CreateClient().GetAsync(
                apiCall.Uri
            );

            var token = JToken.Parse(await resp.Content.ReadAsStringAsync());
            var data = token["data"]; // gets data array from parsed JToken

            // iterates through data, makes models and returns
            return data.Select(ParseBrewery).ToList();

This next method is where the NullPointer error occurs. This method takes the JTokens from the data in the method above. However, the breweryToken parameter throws a NullPointer exception.

// takes JToken and assigns element to returned model
 private static Brewery ParseBrewery(JToken breweryToken) => new Brewery()
        {
            Id = breweryToken["id"].ToObject<string>(),
            Name = breweryToken["name"].ToObject<string>(),
            NameShortDisplay = breweryToken["nameShortDisplay"]?.ToObject<string>(),
            CreateDate = breweryToken["createDate"].ToObject<DateTimeOffset>(),
            UpdateDate = breweryToken["updateDate"]?.ToObject<DateTimeOffset>(),
            Status = breweryToken["status"].ToObject<string>(),
            InBusiness = breweryToken["inBusiness"]?.ToObject<string>() != "N",
            IsVerified = breweryToken["isVerified"].ToObject<string>() != "N",
            Locations = JToken.Parse(breweryToken["locations"].ToString())?.Select(ParseLocation).ToList()
        };

The ParseLocation-method handles the location object (a subobject in each object in the data JToken).

// takes JToken (parsed in ParseBrewery method) and assigns values to returned model
private static Location ParseLocation(JToken locationToken) => new Location()
        {
            Id = locationToken["id"].ToObject<string>(),
            Name = locationToken["name"].ToObject<string>(),
            StreetAddress = locationToken["streetAddress"].ToObject<string>(),
            City = locationToken["locality"].ToObject<string>(),
            Region = locationToken["region"].ToObject<string>(),
            PostalCode = locationToken["postalCode"].ToObject<string>(),
            Website = locationToken["website"].ToObject<string>(),
            Latitude = locationToken["latitude"].ToObject<double>(),
            Longitude = locationToken["longitude"].ToObject<double>(),
            CreateDate = locationToken["createDate"].ToObject<DateTimeOffset>(),
            Status = locationToken["status"].ToObject<string>(),
            Country = ParseCountry(locationToken["country"])
        };

This method again handles a subobject of the location object.

// takes JToken from ParseLocation method and returns filled model
private static Country ParseCountry(JToken countryToken) => new Country()
        {
            IsoCode = countryToken["isoCode"].ToObject<string>(),
            Name = countryToken["name"].ToObject<string>(),
            IsoThree = countryToken["isoThree"]?.ToObject<string>(),
            NumberCode = countryToken["numberCode"]?.ToObject<int>(),
            CreateDate = countryToken["createDate"].ToObject<DateTimeOffset>()
        };

The problem I am running into is, as I mentioned at the corresponding method, somehow the JToken from data seems to become null at some point or another. Debugging through the code shows there is definitely data being returned, but after two or three iterations, it just jumps to the end of the call and throws a NullPointer exception.

I have tried running the variable data through JToken.Parse separately, but I keep running into the same issue. Parsing each separate item in the ParseBrewery method call also returns an error.

I am at a point where I do not know what else I could try to get this to work. I have simply no idea why this could be happening, but I am quite sure it must be a tiny thing as another part of the API which works exactly the same way does return data succesfully.

Hopefully I have provided you with enough info and example code to help understand my problem. If not or if you have any questions, of course feel free to ask and I will answer to the best of my ability!

Thankyou in advance.

thebugsdontwork
  • 401
  • 3
  • 17
  • Can you share the full JSON? I suspect that one of the items in the data array is either null, empty, or missing one or more of the members that your code is expecting to always be there, such as `locations`. Also, have you considered deserializing the JSON directly into your classes instead of using JTokens? I think that would simplify your code quite a bit. You might need a simple converter to handle the conversion of Y/N strings to booleans, but other than that I don't see anything standing in the way. – Brian Rogers Apr 04 '20 at 15:45
  • See [how to get newtonsoft to deserialize yes and no to boolean](https://stackoverflow.com/q/14524669/3744182) for models of a `JsonConverter` you could use to convert a `"Y"` or `"N"` string value to a `bool`. – dbc Apr 09 '20 at 13:52

0 Answers0