REST JSON Response

I am really struggling with getting JSON from a REST service. The JSON looks like this:

[{“ptid”:91,“latitude”:29.6224155426025,“longitude”:-95.7319641113281,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:92,“latitude”:29.6223545074463,“longitude”:-95.7321014404297,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:93,“latitude”:29.6223125457764,“longitude”:-95.7321701049805,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:94,“latitude”:29.6222438812256,“longitude”:-95.732292175293,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:95,“latitude”:29.6221942901611,“longitude”:-95.7323684692383,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:96,“latitude”:29.6221351623535,“longitude”:-95.7324981689453,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:97,“latitude”:29.6221008300781,“longitude”:-95.7326278686523,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:98,“latitude”:29.6220836639404,“longitude”:-95.7327117919922,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:99,“latitude”:29.6220645904541,“longitude”:-95.7328033447266,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1}]

The code is like this:
public IEnumerator Get(string url,)
{
using (UnityWebRequest www = UnityWebRequest.Get(url))
{
www.chunkedTransfer = false;
yield return www.Send();
if (www.isNetworkError)
{
Debug.Log(www.error);:wink:
}
else
{
if (www.isDone)
{
string jsonResult = System.Text.Encoding.UTF8.GetString(www.downloadHandler.data);:wink:

string jsonResult = Encoding.Default.GetString(www.downloadHandler.data);:wink:
SurveyPoint[ ] myObject = JsonUtility.FromJson<SurveyPoint[ ]>(jsonResult);
}
}
}
}

[Serializable]
public class SurveyPoint
{
public int ptid { get; set; }
public double latgitude { get; set; }
public double longitude { get; set; }
public double elevation { get; set; }
public string description { get; set; }
public int type { get; set; }
public int aid { get; set; }
}

The last line causes an error. The error is:JSON must represent an object type. I do not understand. Any help would really be appreciated

Simply put the unity serializer (JsonUtility) has a restriction that the top level element must be a class / struct. so FromJson<SurveyPoint[ ]> doesn’t work but FromJson would work but not in the situation where your json has a root element.

Maybe someone else knows a trick around this using JsonUtility

Solutions I am aware of:

  • Use a different json serializer (e.g. Json.net from the assetstore)
  • If you are in control of the rest API you can change it to { points: [ ] }
  • using string.split or such stuff but I would strongly discourge that as it will break often.

Using Json parser you can validate and parse it.

[
  {
    "ptid": 91,
    "latitude": 29.6224155426025,
    "longitude": -95.7319641113281,
    "elevation": 0,
    "description": "CL",
    "type": 1,
    "aid": 1
  },
  {
    "ptid": 92,
    "latitude": 29.6223545074463,
    "longitude": -95.7321014404297,
    "elevation": 0,
    "description": "CL",
    "type": 1,
    "aid": 1
  },
  {
    "ptid": 93,
    "latitude": 29.6223125457764,
    "longitude": -95.7321701049805,
    "elevation": 0,
    "description": "CL",
    "type": 1,
    "aid": 1
  },
  {
    "ptid": 94,
    "latitude": 29.6222438812256,
    "longitude": -95.732292175293,
    "elevation": 0,
    "description": "CL",
    "type": 1,
    "aid": 1
  },
  {
    "ptid": 95,
    "latitude": 29.6221942901611,
    "longitude": -95.7323684692383,
    "elevation": 0,
    "description": "CL",
    "type": 1,
    "aid": 1
  },
  {
    "ptid": 96,
    "latitude": 29.6221351623535,
    "longitude": -95.7324981689453,
    "elevation": 0,
    "description": "CL",
    "type": 1,
    "aid": 1
  },
  {
    "ptid": 97,
    "latitude": 29.6221008300781,
    "longitude": -95.7326278686523,
    "elevation": 0,
    "description": "CL",
    "type": 1,
    "aid": 1
  },
  {
    "ptid": 98,
    "latitude": 29.6220836639404,
    "longitude": -95.7327117919922,
    "elevation": 0,
    "description": "CL",
    "type": 1,
    "aid": 1
  },
  {
    "ptid": 99,
    "latitude": 29.6220645904541,
    "longitude": -95.7328033447266,
    "elevation": 0,
    "description": "CL",
    "type": 1,
    "aid": 1
  }
]

Knowing structure, you need create correct class.
When I work with JsonUtility

  • I tend to create class for Json format
  • Populate with sample data
  • Then generate Json, to check if format is valid
  • Import back into class
  • Now you should be able know, if you can import your Json.
  • Or in some cases, you may need to add / modify something in a string, before then, to be compatible with JsonUtility.

On side note,
@GWhitch , @gwhitcher_unity please use code tags next time.

That’s a json array. You need to wrap it into an object(/class/struct).

something like

{
    data: [....]
}
2 Likes

I have gotten a little further by adding the “{data … }” to the JSON. It now reads like this:

{
data: [{“ptid”:91,“latitude”:29.6224155426025,“longitude”:-95.7319641113281,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:92,“latitude”:29.6223545074463,“longitude”:-95.7321014404297,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:93,“latitude”:29.6223125457764,“longitude”:-95.7321701049805,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:94,“latitude”:29.6222438812256,“longitude”:-95.732292175293,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:95,“latitude”:29.6221942901611,“longitude”:-95.7323684692383,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:96,“latitude”:29.6221351623535,“longitude”:-95.7324981689453,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:97,“latitude”:29.6221008300781,“longitude”:-95.7326278686523,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:98,“latitude”:29.6220836639404,“longitude”:-95.7327117919922,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1},{“ptid”:99,“latitude”:29.6220645904541,“longitude”:-95.7328033447266,“elevation”:0.0,“description”:“CL”,“type”:1,“aid”:1}]
}

And a I made a class file like this:

[Serializable]
public class SurveyPoint
{
public Point[ ] data;
}

[Serializable]
public class Point
{
public int ptid { get; set; }
public double latgitude { get; set; }
public double longitude { get; set; }
public double elevation { get; set; }
public string description { get; set; }
public int type { get; set; }
public int aid { get; set; }
}

I get an array of the Point type with 9 elements, which is correct. But, all of the elements’ properties have not been filled out. string value is null and all other values are 0.

Unity’s “tiny JSON Lite” built-in package is likely causing you issues, as it fails to handle properties (only fields), dictionaries, hashes, and probably 57 other common things you would reasonably expect it to “just take care of.”

https://docs.unity3d.com/Manual/JSONSerialization.html

Instead I recommend a “real” JSON package such as JSON .NET, free from the asset store.

Erm. Try using public fields, and not a public properties.

Meaning:

[System.Serializable]
public class Point{
    public int ptid;
    public double latgitude;
    public double longitude;
    public double elevation;
    public string description;
    public int type;
    public int aid;
}

Also see:
https://docs.unity3d.com/ScriptReference/JsonUtility.FromJson.html

Exactly why you should switch to JSON .NET. The C# class he posted (the one using properties) is the reference one you get using industry standard tools such as the myriad JSON to C# websites. It silently fails to work with Unity’s deserializer, which is essentially so limited as to be impractical for anyone to use except in the most trivial closed-data-path context (i.e, created in Unity, read in Unity), and certainly NEVER with interoperating with external data sources or sinks.

Holy Smokes that was it! Thank uou so much for helping me get it over the finish line!

Thanks everyone! This has been a struggle. Now I can proceed! This was for a “proof of concept” so It doesn’t have to be a final solution, just one that shows what can be done!

That feels like an overreaction. Json.NET is a third party dependency and those can be undesirable.

If JsonUtility can be made to work, that would suffice in many cases.

Agreed… until it silently (yet predictably) fails deep inside your infrastructure leading to weird errors elsewhere… and days and days go by as you try to isolate what is happening, your release data slipping, your boss yelling at you to track down the problem, your company losing money and user good will as their save games are corrupted…

No thanks!

I liken it to Fisher Price tools. They’re fun to use when you’re four years old banging plastic pegs into a wooden toy.

But you wouldn’t use Fisher Price tools to repair your car, would you?

Again, if it’s internal Unity-to-disk-to-Unity work, you could make the case to use it. The specific question here is in the title coming from an external source (REST API).

Therefore, Unity’s JSON mini-tiny-lite is not a suitable solution for industry-standard JSON use.