41

Assume we have resources like this,

book:
    type: object
    properties:
        author: {type: string}
        isbn: {type: string}
        title: {type: string}

books:
    type: array
    items: book

So, when someone makes a GET on the books resource, we would be returning the following

[{"author": "Dan Brown", "isbn": "123456", "title": "Digital Fortress"},
 {"author": "JK Rowling", "isbn": "234567", "title": "Harry Potter and the Chamber of Secrets"}]

I heard from someone at work that the recommended REST practice is to always return responses as JSON objects, which would mean that our schema for books would look like this,

books:
    type: object
    properties:
        list:
            type: array
            items: book

So, now, response would look like this,

{
    "list": [{"author": "Dan Brown", "isbn": "123456", "title": "Digital Fortress"},
             {"author": "JK Rowling", "isbn": "234567", "title": "Harry Potter and the Chamber of Secrets"}]
}

Which of these is the best REST practice?

  • 1
    is JSON RESTful? you should return html surely? – Ewan Jun 9 '15 at 18:16
  • 3
    @Ewan: The payload doesn't matter. That's what MIME types are for. – Robert Harvey Jun 9 '15 at 18:18
  • 1
    Neither are best practice for REST. REST is made of HATEOAS, which means discoverability of your API. Look up HAL or JSON-LD. – Florian Margaine Jun 10 '15 at 8:03
  • Json-ld : working its way slowly towards WCF – Ewan Jun 10 '15 at 20:27
  • From what I read the wrapping JSON arrays inside an object is a defensive measure against a reported vulnerability in older browsers - haacked.com/archive/2009/06/25/json-hijacking.aspx . This seems to have been fixed in modern browers of today. Better safe than sorry I guess.. – Gishu Sep 14 '17 at 9:05
35

In practice the second option is the best practice. Reason for this is that you cannot extend the resource at all when you just return an array.

For example: If you need to add a count of all records you are already done with the array only approach.

If that happens in one list api then you want to keep it consistent so make all an object then your api becomes more consistent and easier to use for developers.

For example: Let's say a developer writes generic code to use your api to show list and detail pages. He does not want to build an exception because sometimes it's an array and sometimes it's an object with a list property.

This answer in total has nothing todo with principles about rest, hateoas and other protocols but just being real about the data you need to send to the client. If you decide to follow for example hateos then off course stick to their standards (which is also objects btw).

  • 3
    +1 for "being real about data" (and while still recognizing that there is a more technical, more accurate definition for REST). – threed May 24 '17 at 19:49
9

Both

[{"author": "Dan Brown", "isbn": "123456", "title": "Digital Fortress"},{"author": "JK Rowling", "isbn": "234567", "title": "Harry Potter and the Chamber of Secrets"}]

and

{
    "list": [{"author": "Dan Brown", "isbn": "123456", "title": "Digital Fortress"},
         {"author": "JK Rowling", "isbn": "234567", "title": "Harry Potter and the Chamber of Secrets"}]
}

are valid Json. I don't think you should add "list" if it's not needed, it might even be confusing because what's following it is an array, instead of a list.

Best REST practice? The API should give proper response to whatever set in Accept header, and also good documentation.

7

The reason you make your response JSON compliant is that JSON is a defacto standard; any language with a JSON parser can trivially parse it, and if you're using JavaScript, you don't even need a parser since JavaScript understands it natively.

In other words, make it JSON compliant, and you won't have to write your own parser. Further, there will be no surprises when the next developer writes software that consumes the service.

REST doesn't have anything to do with your JSON schema. Either schema is acceptable, from a REST perspective.

  • 9
    Does that answer the question? I read it as "Should I use a json array or a json object as root?". Both can be parsed with json parsers, so your answer doesn't help them decide. – CodesInChaos Jun 10 '15 at 10:53
  • Then it doesn't matter. I've updated my answer. – Robert Harvey Jun 10 '15 at 13:58
  • If we're talking about REST, the schema does not matter as long as it's capable of providing the hypermedia controls for the discovery and manipulation of further resources based on the response alone and no other, out-of-band information... which none of the formats mentioned by the OP seems to do. – toniedzwiedz Dec 9 '15 at 13:30
  • ...and if you're using JavaScript, you don't even need a parser since JavaScript understands it natively. Well, yes and no. JSON is a subset of JavaScript but calling eval instead of using a parser immediately makes you vulnerable to "JSON" that contains malicious code, and parsing is most likely is way more efficient than eval anyways. – Doval Dec 9 '15 at 14:26
5

A dictionary with a single meaningless key "list" and an array value is pointless - return an array instead.

If the same service could return books, CDs or DVDs, then you could return a dictionary with a key "books" and an array value. There could be another key "DVDs" with an array of DVDs. For example if a customer can enquire a list of all their purchases.

If you are certain that the response will only be interpreted as a list of books (if the request said "give me a list of books") then just an array is fine.

5

The second option is also the preferred method for security reasons. Older browsers have a security vulnerability that allows other javascript code on the web page to steal your data if it's returned as a JSON array. So historically the best practice was to not return JSON arrays. In fact, there were some frameworks whose "json-ify" function chooses option 2 by default when you pass in an array.

https://stackoverflow.com/questions/3503102/what-are-top-level-json-arrays-and-why-are-they-a-security-risk

http://ejohn.org/blog/re-securing-json/

1

both are json and adhere to REST. I would make the response more descriptive, in your case change list to books. Or something like this :

{ "responceObject" : {

   results : 2,

    "Books": [
        {"author": "Dan Brown", "isbn": "123456", "title": "Digital Fortress"},
        {"author": "JK Rowling", "isbn": "234567", "title": "Harry Potter and the Chamber of Secrets"}
    ]

}}

Not the answer you're looking for? Browse other questions tagged or ask your own question.