Saturday, May 12, 2018

Understanding JSON Data

New API testers will often be mystified by the assortment of curly braces, colons, and commas that they see in the body of the response to their GET requests.  Trying to create a valid JSON body for a POST request is even more puzzling.  In this week's post, I'll discuss how JSON data is formed and offer up some resources that will make working with JSON easier.

JSON stands for JavaScript Object Notation.  It's simply a way to organize data so that it can easily be parsed by the code.  The fundamental building block in JSON is the name-value pair.  Here are some examples of name-value pairs:

"Name": "Dino"
"Color": "Purple"

A group of name-value pairs is separated by commas, like this:

"FirstName": "Fred",
"LastName": "Flintstone",
"City": "Bedrock"

Note that the final name:value pair does not have a comma.  This is because it's at the end of the group.

An object is simply a grouping of one or more name-value pairs.  The object is represented with curly braces surrounding the name-value pairs.  For example, we might represent a pet object like this:

{
  "Name": "Dino",
  "Type": "Dinosaur",
  "Age": "5",
  "Color": "Purple"
}

An array is a group of objects.  The array is represented with square braces, and the objects inside the array have curly braces.  For example:

"residents": [
  {
    "FirstName": "Fred",
    "LastName": "Flintstone"
  },
  {
    "FirstName": "Barney",
    "LastName": "Rubble"
  },
  {
    "FirstName": "Wilma",
    "LastName": "Flintstone"
  }
]

Notice that Fred Flintstone's last name does not have a comma after it.  This is because the LastName is the last name-value pair in the object.  But, notice that the object that contains Fred Flinstone does have a comma after it, because there are more objects in the array.  Finally, notice that the object that contains Wilma Flintstone does not have a comma after it, because it is the last object in the array.

Not only can an array contain objects, but an object can contain an array.  When you are sending in JSON in the body of an API request, it will always be in the form of an object, which means that it will always begin and end with a curly brace.  Also, name-value pairs, objects, and arrays can be very deeply nested.  It would not be unusual to see something like this contained in a POST for city data:

{
  "residents": [
    {
      "firstName": "Fred",
      "lastName": "Flintstone",
      "contactInfo": {
        "phoneNumber": "555-867-5309",
        "email": "fflintstone@slaterock.com"
      }
    },
    {
      "firstName": "Wilma",
      "lastName": "Flintstone",
      "contactInfo": {
        "phoneNumber": "555-423-4545",
        "email": "wflinstone@dailygranite.com"
      }
    }
  ],
  "pets": [
    {
      "name": "Dino",
      "type": "dinosaur",
      "color": "purple"
    },
    {
      "name": "Hoppy",
      "type": "hopparoo",
      "color": "green"
    }
  ]
}

Notice that the contactInfo is deeply nested in the city object.  If we were testing this API and you wanted to assert that Fred Flintstone's phone number was correct, we would access it like this:

residents[0].contactInfo.phoneNumber

The first array in the city object is the residents array, and Fred is the first resident in the array, so we access him with residents[0].  Next, we move to the contactInfo, and since the contactInfo is an object rather than array, we don't need to specify a number in braces.  Finally, we specify the phoneNumber as the name-value pair within the contactInfo object that we are looking for.

Understanding this nested structure is also important when passing in query parameters in a URL.  For example, if we were to do a GET request on the city object, and we only wanted to have the residents of the city returned, we could use a URL like this:

http://myapp/city/Bedrock?fields=residents

If we wanted to narrow the results further, and only see the first names and email addresses of our residents, we could use a URL like this:

http://myapp/city/Bedrock?fields=residents(firstName), residents(contactInfo(email))

First we are asking for just the residents, and we specify only the firstName within the residents array.  Then we ask for the residents, and we specify only the contactInfo within the residents and only the email within the contactInfo.

Even with the explanations above, you may find working with JSON objects frustrating.  Here are two great, free, tools that can help:

JSONLint- paste any JSON you have into this page, and it will tell you whether or not it is valid JSON.  If it is invalid JSON, it will let you know at what line it becomes invalid.

JSON Pretty Print- it's sometimes hard to format JSON so that the indents are all correct.  Also, having correct indents will make it easier to interpret the JSON.  Whenever you have a JSON object that is not indented correctly, you can paste it into this page and it will format it for you.

Over the last several weeks, we've covered everything you need to know to be successful with API testing.  If you have any unanswered questions, please mention them in the comments section of this post.  Next week, we'll begin a discussion of application security!







4 comments:

  1. Very nicely explained...newbies have trouble decoding JSON files..you article is a must read

    ReplyDelete
    Replies
    1. Thank you so much, Saunak! I was a newbie to JSON a few years ago, and I remember how frustrating it was, so I'm glad you found my post helpful!

      Delete

Testing for IDOR Vulnerabilities

In this week's post, we will learn how to test for IDOR.  IDOR stands for Insecure Direct Object Reference, and it refers to a situation...