Estoy interesado en exponer una interfaz REST directa a colecciones de documentos JSON (piense en CouchDB o Persevere ). El problema con el que me encuentro es cómo manejar la GET
operación en la raíz de la colección si la colección es grande.
Como ejemplo, imagino que estoy exponiendo la Questions
tabla de StackOverflow donde cada fila está expuesta como un documento (no es que exista necesariamente una tabla de este tipo, solo un ejemplo concreto de una colección considerable de 'documentos'). La colección se pondrá a disposición en /db/questions
la API CRUD habitual GET /db/questions/XXX
, PUT /db/questions/XXX
, POST /db/questions
está en juego. La forma estándar de obtener toda la colección es hacerlo, GET /db/questions
pero si ingenuamente vuelca cada fila como un objeto JSON, obtendrá una descarga bastante considerable y mucho trabajo por parte del servidor.
La solución es, por supuesto, la paginación. Dojo ha resuelto este problema en su JsonRestStore mediante una inteligente extensión compatible con RFC2616 de usar el Range
encabezado con una unidad de rango personalizado items
. El resultado es un 206 Partial Content
que devuelve solo el rango solicitado. La ventaja de este enfoque sobre un parámetro de consulta es que deja la cadena de consulta para ... consultas (por ejemplo, GET /db/questions/?score>200
o somesuch, y sí, eso estaría codificado %3E
).
Este enfoque cubre completamente el comportamiento que quiero. El problema es que RFC 2616 especifica que en una respuesta 206 (énfasis mío):
La solicitud DEBE haber incluido un campo de encabezado de Rango ( sección 14.35 ) que indica el rango deseado, y PUEDE haber incluido un campo de encabezado de Rango If ( sección 14.27 ) para hacer que la solicitud sea condicional.
Esto tiene sentido en el contexto del uso estándar del encabezado, pero es un problema porque me gustaría que la respuesta 206 sea la predeterminada para manejar clientes ingenuos / personas aleatorias que exploran.
He revisado el RFC en detalle buscando una solución, pero no estoy contento con mis soluciones y estoy interesado en que SO aborde el problema.
Ideas que he tenido:
- ¡Regresa
200
con unContent-Range
encabezado! - No creo que esto esté mal, pero preferiría un indicador más obvio de que la respuesta es solo Contenido parcial. - Devolución
400 Range Required
: no hay un código de respuesta 400 especial para los encabezados necesarios, por lo que el error predeterminado debe usarse y leerse a mano. Esto también hace que la exploración a través del navegador web (o algún otro cliente como Resty) sea más difícil. - Use un parámetro de consulta : el enfoque estándar, pero espero permitir consultas a la Persevere y esto interrumpe el espacio de nombres de la consulta.
- ¡Solo regresa
206
! - Creo que la mayoría de los clientes no se asustarían, pero prefiero no ir en contra de un DEBE en el RFC - ¡Extiende la especificación! Retorno
266 Partial Content
: se comporta exactamente igual que 206, pero responde a una solicitud que NO DEBE contener elRange
encabezado. Creo que 266 es lo suficientemente alto como para no tener problemas de colisión y tiene sentido para mí, pero no tengo claro si esto se considera tabú o no.
Creo que este es un problema bastante común y me gustaría ver que esto se haga de una manera de facto para que yo o alguien más no esté reinventando la rueda.
¿Cuál es la mejor manera de exponer una colección completa a través de HTTP cuando la colección es grande?
Range = "Range" ":" ranges-specifier
dónde esta última en tools.ietf.org/html/rfc2616#section-14.35.1 se describe simplemente como "byte- range -specifier", que debe comenzar con "bytes-unit", que se define como la cadena "bytes" ".
Content-Range
encabezado se aplica al cuerpo (se puede usar con solicitud al cargar archivos grandes, etc., o como respuesta al descargar). El Range
encabezado se utiliza para solicitar un cierto rango. Uno debe responder con 206
cuándo Range
se incluyó el encabezado en la solicitud. Si no fue así, la respuesta aún puede incluir un Content-Range
encabezado, pero el código de respuesta debería ser 200
. Este encabezado en realidad parece ideal para paginación.