Pasar al contenido principal
ID.R

idiazroncero.com

Paginar resultados de GraphQL en Shopify por la vía rápida

La API GraphQL de Shopify es bastante potente pero hay un aspecto en el que podría mejorar: la paginación de resultados. Algo que, además, es bastante necesario a la hora de no chocar con los límites de la API.

Un modo rápido (si no tienes mucho tiempo para usar bulk operations) es realizar una primera petición simple y poco costosa que nos permita llegar al máximo permitido (250 resultados). Es tan simple que sólo se trata de conseguir todos nuestros nodos (en este caso, orders) y su cursor.

const GET_PAGER_RESULTS = gql `
  query getPagerResults($query: String!) {
    orders(first: 250) {
      edges {
        cursor
        node {
          id
        }
      }
    }
  }
`;

El cursor es un identificador único que nos sirve para identificar la posición de cada ítem en el listado. Esto nos permite «retomar» los resultados desde un punto específico. 

Es decir, si sabemos que el elemento número 4 tiene el cursor 4th-cursor-id y queremos elegir los elementos 4 al 14, nos basta indicar en la query nuestra posición inicial y una longitud de 10 (usando first). Para ello, pasamos 4th-cursor-idafter

const GET_ORDERS = gql `
  query getOrders($cursor: String) {
    orders(first: 10, after: $cursor) { // El cursor indica la posición de inicio.
      edges {
        node {
          id
          name
          tags
          fullyPaid
          // ...etc
          }
        }
      }
    }
  }
`;

Ni Shopify ni Polaris proporcionan un paginador que sea capaz de dividir los N resultados de la query inicial en X páginas de Y elementos, pero sobre nuestra primera query nosotros podemos hacer el cálculo de un modo bastante sencillo y obtener un Array de los cursores en los que comienza cada "página".

// Realizamos nuestra query GET_PAGER_RESULTS y almacenamos los resultados aquí.
const orders; 

// Número de resultados.
const total = orders.edges.length; 

// Resultados por página deseados.
const itemsPerPage = 30:; 

// Cuántas páginas necesitamos. Usamos Ceil para redondear al alza.
let pages = Math.ceil(length / itemsPerPage);

// Filtramos para quedarnos sólo con los cursores de los items que "comienzan" una página nueva.
let cursors = data.orders.edges.filter((item, index) => {
  return index % itemsPerPage === 0;
});

Hecho esto, solo queda renderizar nuestro paginador. Si tenemos Polaris integrado, podemos usar un listado de <Button> dentro de un <ButtonGroup>. Será tan simple como realizar un bucle sobre los cursores y por cada uno de ellos renderizar un elemento que se encargue de la actualización.

// Dentro de un componente de React...
return (
  <ButtonGroup segmented>
    {
      cursors.map((item, index) => {
        return <Button outline
          onClick={() => {
            this.updateCursor(item.cursor);
          }}>
          { index + 1 }
        </Button>
      })
    }
    </ButtonGroup>
)}

En este ejemplo, cada uno de los botones del paginador está ligado con un evento onClick  que actualiza el estado del componente al realizar una nueva query GET_ORDERS con el nuevo valor de $cursor