Jaki jest najlepszy sposób na zwrócenie tablicy jako odpowiedzi w RESTful API?

40

Załóżmy, że mamy takie zasoby,

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

books:
    type: array
    items: book

Tak więc, gdy ktoś zrobi GETzasób książek, zwracamy następujące

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

Słyszałem od kogoś w pracy, że zalecaną praktyką REST jest zawsze zwracanie odpowiedzi jako obiektów JSON, co oznaczałoby, że nasz schemat bookswyglądałby tak,

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

Tak więc odpowiedź wyglądałaby tak:

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

Która z nich jest najlepszą praktyką REST?

urodzony krzyżowiec
źródło
1
jest JSON RESTful? powinieneś zwrócić HTML?
Ewan
3
@Ewan: Ładowność nie ma znaczenia. Po to są typy MIME.
Robert Harvey,
1
Nie są też najlepszą praktyką dla REST. REST składa się z HATEOAS, co oznacza wykrywalność twojego API. Wyszukaj HAL lub JSON-LD.
Florian Margaine,
Json-ld: powoli zmierza w kierunku WCF
Ewan
Z tego, co przeczytałem, zawijanie tablic JSON wewnątrz obiektu stanowi środek obronny przeciwko zgłoszonej podatności w starszych przeglądarkach - haacked.com/archive/2009/06/25/json-hijacking.aspx . Wydaje się, że zostało to naprawione we współczesnych przeglądarkach. Chyba lepiej, niż przepraszam ...
Gishu

Odpowiedzi:

35

W praktyce druga opcja jest najlepszą praktyką. Powodem tego jest to, że nie można w ogóle rozszerzyć zasobu, po prostu zwracając tablicę.

Na przykład: jeśli chcesz dodać liczbę wszystkich rekordów, które zostały już wykonane przy użyciu tylko macierzy.

Jeśli dzieje się tak w przypadku jednego interfejsu API listy, to chcesz zachować spójność, więc zrób cały obiekt, a następnie interfejs API stanie się bardziej spójny i łatwiejszy w użyciu dla programistów.

Na przykład: Załóżmy, że programista pisze ogólny kod, aby użyć interfejsu API do wyświetlenia listy i stron ze szczegółami. Nie chce budować wyjątku, ponieważ czasami jest to tablica, a czasem obiekt z właściwością list.

Ta odpowiedź nie ma nic wspólnego z zasadami dotyczącymi odpoczynku, nienawiści i innych protokołów, ale jest prawdziwa w odniesieniu do danych, które należy wysłać do klienta. Jeśli zdecydujesz się na przykład na hateos, to oczywiście trzymaj się ich standardów (które również są obiektami btw).

Luc Franken
źródło
3
+1 za „bycie prawdziwym na temat danych” (i przy jednoczesnym uznaniu, że istnieje bardziej techniczna, dokładniejsza definicja REST).
wystąpił
8

Obie

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

i

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

są ważne Json. Nie sądzę, że powinieneś dodać „listę”, jeśli nie jest potrzebna, może nawet być myląca, ponieważ to, co następuje po niej, to tablica zamiast listy.

Najlepsza praktyka REST? Interfejs API powinien dawać właściwą odpowiedź na dowolny zestaw nagłówka Accept, a także dobrą dokumentację.

imel96
źródło
7

Powodem, dla którego twoja odpowiedź jest zgodna z JSON, jest to, że JSON jest standardem defacto; dowolny język z analizatorem składni JSON może go w prosty sposób przeanalizować, a jeśli używasz JavaScript, nie potrzebujesz nawet analizatora składni, ponieważ JavaScript rozumie go natywnie.

Innymi słowy, dostosuj go do JSON, a nie będziesz musiał pisać własnego parsera. Co więcej, nie będzie niespodzianek, gdy następny programista napisze oprogramowanie korzystające z usługi.

REST nie ma nic wspólnego ze schematem JSON. Każdy schemat jest akceptowalny z perspektywy REST.

Robert Harvey
źródło
9
Czy to odpowiada na pytanie? Przeczytałem go jako „Czy powinienem użyć tablicy Json lub obiektu Json jako root?”. Oba można analizować za pomocą parserów json, więc twoja odpowiedź nie pomoże im zdecydować.
CodesInChaos
To nie ma znaczenia. Zaktualizowałem swoją odpowiedź.
Robert Harvey
Jeśli mówimy o REST, schemat nie ma znaczenia, o ile jest on w stanie zapewnić kontrolę hipermedialną w celu wykrywania i manipulowania dalszymi zasobami na podstawie samej odpowiedzi i żadnych innych informacji poza pasmem ... które wydaje się, że żaden z formatów wymienionych przez PO nie działa.
toniedzwiedz
...and if you're using JavaScript, you don't even need a parser since JavaScript understands it natively.Cóż, tak i nie. JSON jest podzbiorem JavaScript, ale wywołanie evalzamiast użycia parsera powoduje natychmiastową podatność na „JSON”, który zawiera złośliwy kod, a parsowanie najprawdopodobniej jest o wiele bardziej wydajne niż evaljakikolwiek inny.
Doval,
5

Słownik z pojedynczą, pozbawioną znaczenia „listą” kluczy i wartością tablicy jest bezcelowy - zamiast tego zwraca tablicę.

Jeśli ta sama usługa może zwrócić książki, płyty CD lub DVD, możesz zwrócić słownik z kluczem „książki” i wartością tablicy. Może istnieć inny kluczowy „dysk DVD” z szeregiem dysków DVD. Na przykład, jeśli klient może uzyskać listę wszystkich swoich zakupów.

Jeśli masz pewność, że odpowiedź zostanie zinterpretowana jedynie jako lista książek (jeśli w żądaniu było napisane „daj mi listę książek”), wystarczy tablica.

gnasher729
źródło
5

Druga opcja jest również preferowaną metodą ze względów bezpieczeństwa. Starsze przeglądarki mają lukę w zabezpieczeniach, która pozwala innemu kodowi javascript na stronie internetowej ukraść dane, jeśli zostaną zwrócone jako tablica JSON. Tak więc historycznie najlepszą praktyką było nie zwracanie tablic JSON. W rzeczywistości istniały pewne frameworki, których funkcja „json-ify” wybiera domyślnie opcję 2 podczas przekazywania w tablicy.

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/

Głaskanie pod brodę
źródło
1

oba są json i stosują się do REST. Chciałbym, aby odpowiedź była bardziej opisowa, w twoim przypadku zmień listę na książki. Lub coś w tym stylu :

{ "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"}
    ]

}}
MeganFoxObama
źródło