¿Cuál es la mejor manera de devolver una matriz como respuesta en una API RESTful?

41

Supongamos que tenemos recursos como este,

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

books:
    type: array
    items: book

Entonces, cuando alguien hace un GETrecurso en los libros, estaríamos devolviendo lo siguiente

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

Escuché de alguien en el trabajo que la práctica REST recomendada es siempre devolver respuestas como objetos JSON, lo que significaría que nuestro esquema booksse vería así,

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

Entonces, ahora, la respuesta se vería así,

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

¿Cuál de estas es la mejor práctica REST?

cruzado nacido
fuente
1
es JSON RESTful? deberías devolver html seguramente?
Ewan
3
@Ewan: La carga útil no importa. Para eso están los tipos MIME.
Robert Harvey
1
Tampoco lo son las mejores prácticas para REST. REST está hecho de HATEOAS, lo que significa la capacidad de detección de su API. Busque HAL o JSON-LD.
Florian Margaine
Json-ld: avanzando lentamente hacia WCF
Ewan
Por lo que leí, las matrices JSON envolventes dentro de un objeto es una medida defensiva contra una vulnerabilidad reportada en navegadores antiguos: haacked.com/archive/2009/06/25/json-hijacking.aspx . Esto parece haberse solucionado en los navegadores modernos de hoy. Mejor prevenir que lamentar, supongo ...
Gishu

Respuestas:

35

En la práctica, la segunda opción es la mejor práctica. La razón de esto es que no puede extender el recurso cuando solo devuelve una matriz.

Por ejemplo: si necesita agregar un recuento de todos los registros, ya ha terminado con el enfoque de solo matriz.

Si eso sucede en una API de lista, entonces desea mantenerla coherente para que todo sea un objeto, entonces su API se volverá más consistente y fácil de usar para los desarrolladores.

Por ejemplo: supongamos que un desarrollador escribe código genérico para usar su API para mostrar listas y páginas de detalles. No quiere crear una excepción porque a veces es una matriz y otras es un objeto con una propiedad de lista.

Esta respuesta en total no tiene nada que ver con los principios sobre descanso, hateoas y otros protocolos, sino solo ser real sobre los datos que necesita enviar al cliente. Si decide seguir, por ejemplo, los odios, entonces, por supuesto, cumpla con sus estándares (que también son objetos, por cierto).

Luc Franken
fuente
3
+1 para "ser real acerca de los datos" (y aun reconociendo que hay una definición más técnica y precisa para REST).
trillado
9

Ambos

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

y

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

son válidos Json. No creo que deba agregar "lista" si no es necesario, incluso podría ser confuso porque lo que sigue es una matriz, en lugar de una lista.

¿La mejor práctica de descanso? La API debe dar una respuesta adecuada a cualquier conjunto en el encabezado Aceptar, y también buena documentación.

imel96
fuente
7

La razón por la que hace que su respuesta sea compatible con JSON es que JSON es un estándar de facto; cualquier lenguaje con un analizador JSON puede analizarlo trivialmente, y si está usando JavaScript, ni siquiera necesita un analizador ya que JavaScript lo entiende de forma nativa.

En otras palabras, haga que sea compatible con JSON, y no tendrá que escribir su propio analizador. Además, no habrá sorpresas cuando el próximo desarrollador escriba software que consuma el servicio.

REST no tiene nada que ver con su esquema JSON. Cualquiera de los dos esquemas es aceptable, desde una perspectiva REST.

Robert Harvey
fuente
9
¿Eso responde a la pregunta? Lo leí como "¿Debo usar una matriz json o un objeto json como root?". Ambos se pueden analizar con analizadores json, por lo que su respuesta no los ayuda a decidir.
CodesInChaos
Entonces no importa. He actualizado mi respuesta.
Robert Harvey
Si hablamos de REST, el esquema no importa siempre y cuando sea capaz de proporcionar los controles hipermedia para el descubrimiento y la manipulación de recursos adicionales basados ​​en la respuesta sola y no en otra información fuera de banda ... que ninguno de los formatos mencionados por el OP parece funcionar.
toniedzwiedz
...and if you're using JavaScript, you don't even need a parser since JavaScript understands it natively.Pues sí y no. JSON es un subconjunto de JavaScript, pero llamar en evallugar de usar un analizador inmediatamente lo hace vulnerable a "JSON" que contiene código malicioso, y el análisis probablemente sea mucho más eficiente que de evaltodos modos.
Doval
5

Un diccionario con una única "lista" de claves sin sentido y un valor de matriz no tiene sentido; en su lugar, devuelva una matriz.

Si el mismo servicio puede devolver libros, CD o DVD, puede devolver un diccionario con una clave "libros" y un valor de matriz. Podría haber otra clave "DVD" con una variedad de DVD. Por ejemplo, si un cliente puede consultar una lista de todas sus compras.

Si está seguro de que la respuesta solo se interpretará como una lista de libros (si la solicitud decía "dame una lista de libros"), entonces solo una matriz está bien.

gnasher729
fuente
5

La segunda opción también es el método preferido por razones de seguridad. Los navegadores más antiguos tienen una vulnerabilidad de seguridad que permite que otros códigos javascript en la página web roben sus datos si se devuelven como una matriz JSON. Históricamente, la mejor práctica era no devolver matrices JSON. De hecho, hubo algunos marcos cuya función "json-ify" elige la opción 2 de forma predeterminada cuando pasa una matriz.

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/

Arrojar
fuente
1

ambos son json y se adhieren a REST. Yo haría la respuesta más descriptiva, en su caso, cambie la lista a libros. O algo como esto :

{ "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
fuente