71

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?

5
  • 2
    is JSON RESTful? you should return html surely?
    – Ewan
    Commented Jun 9, 2015 at 18:16
  • 4
    @Ewan: The payload doesn't matter. That's what MIME types are for. Commented Jun 9, 2015 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. Commented Jun 10, 2015 at 8:03
  • Json-ld : working its way slowly towards WCF
    – Ewan
    Commented Jun 10, 2015 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
    Commented Sep 14, 2017 at 9:05

6 Answers 6

71

In practice, the second option is the best practice. The 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 to do 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 HATEOAS then, of course, stick to their standards (which are also objects btw).

2
  • 6
    +1 for "being real about data" (and while still recognizing that there is a more technical, more accurate definition for REST).
    – threed
    Commented May 24, 2017 at 19:49
  • 2
    +1 See for example how Django REST Framework handles pagination. If you just use an array you don't have anywhere to put count, next and previous.
    – Carl
    Commented Jul 17, 2020 at 15:53
11

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.

1
  • The first one is not an object. It is an array. If you go with the first, you will be unable to add metadata later (e.g.: total item count without pagination)
    – pihentagy
    Commented Aug 1, 2022 at 14:13
11

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/

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.

4
  • 11
    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. Commented Jun 10, 2015 at 10:53
  • Then it doesn't matter. I've updated my answer. Commented Jun 10, 2015 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. Commented Dec 9, 2015 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
    Commented Dec 9, 2015 at 14:26
6

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.

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.