2011-11-28 10 views
32

Antecedentes¿Cuáles son las mejores prácticas para agregar metadatos a una respuesta RESTful JSON?

Estamos construyendo una API reparador que debe devolver los objetos de datos como JSON. En la mayoría de los casos, está bien devolver el objeto de datos, pero en algunos casos, f.ex. paginación o validación, necesitamos agregar algunos metadatos a la respuesta.

Lo que tenemos hasta el momento

Hemos envuelto todas las respuestas JSON como este ejemplo:

{ 
    "metadata" :{ 
     "status": 200|500, 
     "msg": "Some message here", 
     "next": "http://api.domain.com/users/10/20" 
     ... 
    }, 
    "data" :{ 
     "id": 1001, 
     "name": "Bob" 
    } 
} 

Pros

  • podemos añadir metadatos útiles para la respuesta

Contras

  • En la mayoría de los casos no es necesario el campo de metadatos, y que añade complejidad al formato JSON
  • Ya que no es un objeto de datos más, sino más bien como una respuesta con envoltura , no podemos utilizar la respuesta de inmediato en f.ex backbone.js sin extraer el objeto de datos.

Pregunta

Lo que es de las mejores prácticas para añadir metadatos a una respuesta JSON?

ACTUALIZACIÓN

Lo que tengo hasta ahora de respuestas a continuación:

  • Retire la metadata.status un retorno del código de respuesta HTTP en el protocolo HTTP en lugar (200, 500 ...)
  • Agregar mensaje de error al cuerpo de una repsonse http 500
  • Para la paginación es natural que algunos metadatos cuenten sobre la estructura de paginación, y datos anidados en esa estructura
  • pequeña cantidad de metadatos puede ser añadido a la cabecera HTTP (X-algo)
+0

¿Sabía que su ejemplo no es JSON? – JeremyP

+0

gracias, es actualizado –

+1

¿Podría entrar en más detalles sobre sus posibles casos de uso y por qué el código de estado HTTP y la configuración de los encabezados de respuesta apropiados no serían adecuados? – Charlie

Respuesta

0

Tuvimos el mismo caso de uso, en el que teníamos que añadir metadatos paginación para una respuesta JSON. Terminamos creando un tipo de colección en Backbone que podría manejar esta información, y una envoltura liviana en el lado de Rails. Este ejemplo simplemente agrega los metadatos al objeto de colección para referencia de la vista.

Por ello hemos creado una clase algo Colección Backbone como esto

// Example response: 
// { num_pages: 4, limit_value: 25, current_page: 1, total_count: 97 
// records: [{...}, {...}] } 

PageableCollection = Backbone.Collection.extend({ 
    parse: function(resp, xhr) { 
    this.numPages = resp.num_pages; 
    this.limitValue = resp.limit_value; 
    this.currentPage = resp.current_page; 
    this.totalCount = resp.total_count; 
    return resp.records; 
    } 
}); 

Y luego hemos creado esta clase simple en el lado de los carriles, para emitir los metadatos cuando paginado con Kaminari

class PageableCollection 
    def initialize (collection) 
    @collection = collection 
    end 
    def as_json(opts = {}) 
    { 
     :num_pages => @collection.num_pages 
     :limit_value => @collection.limit_value 
     :current_page => @collection.current_page, 
     :total_count => @collection.total_count 
     :records => @collection.to_a.as_json(opts) 
    } 
    end 
end 

Usted Úselo en un controlador como este

class ThingsController < ApplicationController 
    def index 
    @things = Thing.all.page params[:page] 
    render :json => PageableCollection.new(@things) 
    end 
end 

Enjoy. Esperamos que te sea útil.

+0

¿No sería mejor agregar enlaces de paginación en la respuesta en lugar de incrustar la lógica de solicitud de paginación en el cliente? –

4

A lo largo de las líneas de @ comentarios de Charlie: para la parte de la paginación de su pregunta que todavía tienen que cocer los metadatos en el somhow respuesta, pero los status y message atributos aquí son algo redundante, puesto que ya están cubiertos por la HTTP protocolo en sí (estado 200 - modelo encontrado, 404 - modelo no encontrado, 403 - privs insuficientes, se entiende la idea) (consulte spec). Incluso si su servidor devuelve una condición de error, puede enviar la pieza message como cuerpo de respuesta. Estos dos campos cubrirán gran parte de sus necesidades de metadatos.

Personalmente, he tendido hacia (ab) el uso de encabezados HTTP personalizados para piezas más pequeñas de metadatos (con un prefijo X-), pero supongo que el límite donde eso se vuelve poco práctico es bastante bajo.

Tengo expanded un poco acerca de esto en una pregunta con un alcance menor, pero creo que los puntos siguen siendo válidos para esta pregunta.

+0

Aparentemente el prefijo con 'X-' es [ya no se recomienda] (http://stackoverflow.com/a/3561399/320036). – z0r

+1

@ z0r La afirmación es controvertida, según las respuestas del enlace. –

8

usted tiene varios medios para pasar metadatos en una API REST:

  1. código de estado HTTP
  2. encabezados
  3. respuesta del cuerpo

Para el metadata.status, utilice el código de estado HTTP Código, ¡para eso sirve! Si los metadatos se refieren a toda la respuesta, puede agregarlos como campos de encabezado. Si los metadatos se refieren solo a parte de la respuesta, deberá incrustar los metadatos como parte del objeto. DO NOT envuelve toda la respuesta en un sobre artificial y divide el contenedor en datos y metadatos.

Y finalmente, sea coherente en su API con las elecciones que realice.

Un buen ejemplo es un GET en una colección completa con paginación. GET/items Puede devolver el tamaño de la colección y la página actual en encabezados personalizados. Y enlaces de paginación en la cabecera estándar: Enlace

Link: <https://api.mydomain.com/v1/items?limit=25&offset=25>; rel=next 

El problema con este enfoque es cuando se necesita añadir metadatos referencia a elementos específicos de la respuesta. En ese caso simplemente incrústelo en el objeto mismo. Y para tener un enfoque coherente ... agregue siempre todos los metadatos a la respuesta.Así que volviendo a los GET/artículos, imagina que cada elemento ha creado y metadatos actualización:

{ 
    items:[ 
    { 
     "id":"w67e87898dnkwu4752igd", 
     "message" : "some content", 
     "_created": "2014-02-14T10:07:39.574Z", 
     "_updated": "2014-02-14T10:07:39.574Z" 
    }, 
    ...... 
    { 
     "id":"asjdfiu3748hiuqdh", 
     "message" : "some other content", 
     "_created": "2014-02-14T10:07:39.574Z", 
     "_updated": "2014-02-14T10:07:39.574Z" 
    } 
    ], 
    "_total" :133, 
    "_links" :[ 
    { 
     "next" :{ 
      href : "https://api.mydomain.com/v1/items?limit=25&offset=25" 
     } 
    ] 
} 

Tenga en cuenta que una respuesta colección es un caso especial. Si agrega metadatos a una colección, la colección ya no se puede devolver como una matriz, debe ser un objeto con una matriz. ¿Por qué un objeto? porque desea agregar algunos atributos de metadatos.

Comparar con los metadatos en los elementos individuales. Nada cerca de envolver a la entidad. Simplemente agrega algunos atributos al recurso.

Una convención es diferenciar campos de control o metadatos. Podría prefijar esos campos con un guión bajo.

Cuestiones relacionadas