Paginación en una aplicación web REST

Esta es una reformulación más genérica de esta pregunta (con la eliminación de las partes específicas de Rails)

No estoy seguro de cómo implementar la paginación en un recurso en una aplicación web RESTful. Suponiendo que tengo un recurso llamado products , ¿cuál de los siguientes cree que es el mejor enfoque y por qué?

1. Usar solo cadenas de consulta

p.ej. http://application/products?page=2&sort_by=date&sort_how=asc
El problema aquí es que no puedo usar el almacenamiento en caché de página completa y también la URL no es muy limpia y fácil de recordar.

2. Usar páginas como recursos y cadenas de consulta para ordenar

p.ej. http://application/products/page/2?sort_by=date&sort_how=asc
En este caso, el problema que se ve es que http://application/products/pages/1 no es un recurso único ya que el uso de sort_by=price puede arrojar un resultado totalmente diferente y aún no puedo usar el almacenamiento en caché de la página.

3. Usar páginas como recursos y un segmento URL para ordenar

p.ej. http://application/products/by-date/page/2
Personalmente, no veo ningún problema en utilizar este método, pero alguien me advirtió que no es una buena forma de hacerlo (no dio ninguna razón, así que si sabes por qué no es recomendable, házmelo saber)

Cualquier sugerencia, opinión, crítica es más que bienvenida. Gracias.

Creo que el problema con la versión 3 es más un problema de “punto de vista”: ¿ves la página como el recurso o los productos en la página?

Si ve la página como el recurso, es una solución perfectamente perfecta, ya que la consulta de la página 2 siempre arrojará la página 2.

Pero si ve los productos en la página como el recurso, tiene el problema de que los productos en la página 2 podrían cambiar (productos antiguos eliminados, o lo que sea), en este caso, el URI no siempre devuelve el mismo recurso (s).

Por ejemplo, un cliente almacena un enlace a la página X de la lista de productos, la próxima vez que se abra el enlace, es posible que el producto en cuestión ya no esté en la página X.

Estoy de acuerdo con Fionn, pero daré un paso más y me diré que la página no es un recurso, es una propiedad de la solicitud. Eso me hace elegir la cadena de consulta de la opción 1 solamente. Simplemente se siente bien. Me gusta mucho cómo la API de Twitter está estructurada de manera relajada. No demasiado simple, no demasiado complicado, bien documentado. Para bien o para mal, es mi diseño de “ir a” cuando estoy cerca de hacer algo de una manera contra otra.

HTTP tiene un gran rango de encabezado que también es adecuado para la paginación. Puedes enviar

 Range: pages=1 

tener solo la primera página. Eso puede obligarte a replantearte qué es una página. Quizás el cliente quiera una gama diferente de artículos. El encabezado del rango también funciona para declarar un pedido:

 Range: products-by-date=2009_03_27- 

para obtener todos los productos más nuevos que esa fecha o

 Range: products-by-date=0-2009_11_30 

para obtener todos los productos anteriores a esa fecha. ‘0’ probablemente no sea la mejor solución, pero RFC parece querer algo para el inicio del rango. Puede haber analizadores HTTP desplegados que no analizarían unidades = -range_end.

Si los encabezados no son una opción (aceptable), reconozco que la primera solución (todo en la cadena de consulta) es una forma de tratar con las páginas. Pero, por favor, normalice cadenas de consulta (ordenar (clave = valor) pares en orden alfabético). Esto resuelve el problema de diferenciación “? A = 1 & b = x” y “? B = x & a = 1”.

La opción 1 parece ser la mejor, en la medida en que su aplicación vea la paginación como una técnica para producir una vista diferente del mismo recurso.

Habiendo dicho eso, el esquema de URL es relativamente insignificante. Si está diseñando su aplicación para ser dirigida por hipertexto (ya que todas las aplicaciones REST deben ser por definición), entonces su cliente no construirá ningún URI por sí mismo. En cambio, su aplicación le dará los enlaces al cliente y el cliente los seguirá.

Un tipo de enlace que su cliente puede proporcionar es un enlace de paginación.

El efecto secundario agradable de todo esto es que, incluso si cambia de opinión sobre la estructura del URI de paginación e implementa algo totalmente diferente la próxima semana, sus clientes pueden seguir trabajando sin ninguna modificación.

Siempre he usado el estilo de la opción 1. El almacenamiento en caché no ha sido una preocupación ya que los datos cambian con frecuencia de todos modos en mi caso. Si permite que el tamaño de la página sea configurable, nuevamente los datos no se pueden almacenar en caché.

No encuentro la url difícil de recordar o sucia. Para mí, este es un buen uso de los parámetros de consulta. El recurso es claramente una lista de productos y los parámetros de consulta solo indican cómo desea que se muestre la lista, ordenada y qué página.

Es extraño que nadie haya señalado que la Opción 3 tiene parámetros en un orden específico. http // application / products / Date / Descending / Name / Ascending / page / 2 y http // application / products / Name / Ascending / Date / Descending / page / 2

apuntan al mismo recurso, pero tienen URL completamente diferentes.

Para mí, la Opción 1 parece ser la más aceptable, ya que separa claramente “Lo que quiero” y “Cómo lo quiero” (Incluso tiene un signo de interrogación entre ellos jajaja). El almacenamiento en caché de página completa se puede implementar utilizando la URL completa (todas las opciones sufrirán el mismo problema de todos modos).

Con el enfoque Parámetros-en-URL, el único beneficio es la URL limpia. Aunque tienes que encontrar la manera de codificar los parámetros y decodificarlos sin pérdida. Por supuesto, puede ir con URLencode / decode, pero hará que las URL sean feas de nuevo 🙂

Prefiero usar los parámetros de consulta offset y limit.

offset : para el índice del artículo en la colección.

límite : para el recuento de elementos.

El cliente simplemente puede seguir actualizando el desplazamiento de la siguiente manera

 offset = offset + limit 

para la próxima página.

La ruta se considera el identificador de recursos. Y una página no es un recurso sino un subconjunto de la colección de recursos. Como la paginación es generalmente una solicitud GET, los parámetros de consulta son más adecuados para la paginación en lugar de los encabezados.

Yo uso metamug Ellos tienen esto configurable. Paginación en metamug de consulta seleccionada

Actualmente estoy usando un esquema similar a este en mis aplicaciones ASP.NET MVC:

por ejemplo, http://application/products/by-date/page/2

específicamente, es: http://application/products/Date/Ascending/3

Sin embargo, no estoy muy contento con la inclusión de paginación y clasificación de información en la ruta de esta manera.

La lista de artículos (productos en este caso) es mutable. es decir, la próxima vez que alguien regrese a una url que incluye parámetros de paginación y clasificación, los resultados que obtengan pueden haber cambiado. Por lo tanto, se pierde la idea de http://application/products/Date/Ascending/3 como una URL única que apunta a un conjunto de productos definido e inmutable.

Buscando las mejores prácticas encontré este sitio:

http://www.restapitutorial.com

En la página de recursos hay un enlace para descargar un .pdf que contiene las mejores prácticas de REST sugeridas por el autor. En el cual, entre otras cosas, hay una sección sobre paginación.

El autor sugiere agregar soporte tanto para usar un encabezado de rango como para usar parámetros de cadena de consulta.

Solicitud

Ejemplo de encabezado HTTP:

 Range: items=0-24 

Ejemplo de parámetros de cadena de consulta:

 GET http://api.example.com/resources?offset=0&limit=25 

Donde el desplazamiento es el número de artículo inicial y el límite es la cantidad máxima de artículos que se devolverán.

Respuesta

La respuesta debe incluir un encabezado Content-Range que indique cuántos elementos se devuelven y cuántos elementos totales aún no se han recuperado.

Ejemplos de encabezado HTTP:

 Content-Range: items 0-24/66 Content-Range: items 40-65/* 

En .pdf hay algunas otras sugerencias para casos más específicos.

Tiendo a estar de acuerdo con slf en que “página” no es realmente un recurso. Por otro lado, la opción 3 es más limpia, más fácil de leer, y el usuario puede adivinarla más fácilmente e incluso escribirla si es necesario. Estoy dividido entre las opciones 1 y 3, pero no veo ninguna razón para no usar la opción 3.

Además, aunque se ven bien, una desventaja del uso de parámetros ocultos, como alguien mencionó, en lugar de cadenas de consulta o segmentos de URL es que el usuario no puede marcar o vincular directamente a una página en particular. Eso puede o no ser un problema dependiendo de la aplicación, pero es algo a tener en cuenta.

He usado la solución 3 antes (escribo MUCHAS aplicaciones django). Y no creo que haya nada de malo en eso. Es tan generable como los otros dos (en caso de que necesite hacer algo de raspado masivo o similar) y se ve más limpio. Además, sus usuarios pueden adivinar URL (si es una aplicación pública), y a las personas les gusta poder ir directamente a donde quieren, y las adivinanzas de url se sienten empoderantes.

Utilizo en mis proyectos las siguientes URL:

 http://application/products?page=2&sort=+field1-field2 

lo que significa: “dame la página la segunda página ordenada ascendiendo por campo1 y luego descendiendo por campo2”. O si necesito aún más flexibilidad uso:

 http://application/products?skip=20&limit=20&sort=+field1-field2 
Intereting Posts