Estou interessado em expor uma interface REST direta a coleções de documentos JSON (pense em CouchDB ou Persevere ). O problema que eu estou enfrentando é como lidar com a GET
operação na raiz da coleção, se a coleção for grande.
Como exemplo, finja que estou expondo a Questions
tabela do StackOverflow em que cada linha é exposta como um documento (não que exista necessariamente uma tabela desse tipo, apenas um exemplo concreto de uma coleção considerável de 'documentos'). A coleção seria disponibilizado na /db/questions
com a api CRUD de costume GET /db/questions/XXX
, PUT /db/questions/XXX
, POST /db/questions
está em jogo. A maneira padrão de obter toda a coleção é, GET /db/questions
mas se isso ingenuamente despejar cada linha como um objeto JSON, você terá um download bastante considerável e muito trabalho por parte do servidor.
A solução é, obviamente, a paginação. O Dojo resolveu esse problema em seu JsonRestStore por meio de uma inteligente extensão compatível com RFC2616, usando o Range
cabeçalho com uma unidade de intervalo personalizada items
. O resultado é um 206 Partial Content
que retorna apenas o intervalo solicitado. A vantagem dessa abordagem sobre um parâmetro de consulta é que ele deixa a string de consulta para ... consultas (por exemplo, GET /db/questions/?score>200
ou algo assim, e sim, isso seria codificado %3E
).
Essa abordagem cobre completamente o comportamento que eu quero. O problema é que o RFC 2616 especifica que, em uma resposta 206 (ênfase minha):
O pedido DEVE ter incluído um campo de cabeçalho Range ( seção 14.35 ) indicando o intervalo desejado, e PODE ter incluído um campo de cabeçalho If-Range ( seção 14.27 ) para tornar o pedido condicional.
Isso faz sentido no contexto do uso padrão do cabeçalho, mas é um problema, porque eu gostaria que a resposta 206 fosse o padrão para lidar com clientes ingênuos / pessoas aleatórias explorando.
Analisei detalhadamente a RFC em busca de uma solução, mas fiquei insatisfeito com minhas soluções e estou interessado na opinião do SO sobre o problema.
Idéias que tive:
- Retorne
200
com umContent-Range
cabeçalho! - Não acho que isso esteja errado, mas eu prefiro um indicador mais óbvio de que a resposta é apenas Conteúdo Parcial. - Retorno
400 Range Required
- Não há um código de resposta especial 400 para os cabeçalhos necessários; portanto, o erro padrão deve ser usado e lido manualmente. Isso também dificulta a exploração via navegador da Web (ou outro cliente como o Resty). - Use um parâmetro de consulta - A abordagem padrão, mas espero permitir consultas a la Persevere e isso corta o espaço para nome da consulta.
- Basta voltar
206
! - Eu acho que a maioria dos clientes não iria surtar, mas eu prefiro não ir contra um DEVE na RFC - Estenda a especificação! Retorno
266 Partial Content
- se comporta exatamente como o 206, mas é em resposta a uma solicitação que NÃO DEVE conter oRange
cabeçalho. Eu acho que o 266 é alto o suficiente para não ter problemas com colisões e isso faz sentido para mim, mas não tenho certeza se isso é considerado tabu ou não.
Eu acho que esse é um problema bastante comum e gostaria de ver isso feito de uma maneira de fato, para que eu ou outra pessoa não esteja reinventando a roda.
Qual é a melhor maneira de expor uma coleção completa via HTTP quando a coleção é grande?
Range = "Range" ":" ranges-specifier
onde o último em tools.ietf.org/html/rfc2616#section-14.35.1 é descrito meramente como "byte-range-specifier", que deve começar com "bytes-unit", que é definido como a string "bytes "
Content-Range
cabeçalho se aplica ao corpo (pode ser usado com solicitação ao fazer upload de arquivos grandes etc, ou como resposta ao fazer o download). O Range
cabeçalho é usado para solicitar um determinado intervalo. Deve-se responder 206
quando o Range
cabeçalho foi incluído na solicitação. Caso contrário, a resposta ainda pode incluir um Content-Range
cabeçalho, mas o código de resposta deve estar 200
. Na verdade, esse cabeçalho parece ideal para paginação.