Search code examples
javascriptgraphqlkoa

Cursor based pagination graphql


I am retrieving data from graphql over a koa-server. For that, I wrote a function requestData(token, queryName, cursor) to call the graphql.

I would like to repeat the request until the cursor is null or undefined.

I always need to use the last cursor:

lastCursor = edges[edges.length - 1].cursor;

In the terminal I am getting following outputs:

null
eyJsYXN0X2lkIjo2MTQzNTk3ODcxMjc0LCJsYXN0X3ZhbHVlIjoiNjE0MzU5Nzg3MTI3NCJ9

I am getting this output even though I have more data. Can someone help me figure out what is wrong with my code?

server.js part

  router.post('/getAllProducts', bodyParser(), async (ctx, next) => {
    let data;
    let edges;
    let lastCursor = null;
    const { accessToken } = ctx.session;
    ctx.response.status = 200;

    requestData(accessToken, GET_ALL_PRODUCTS, lastCursor).then((res) => {
      data = res.data.data;
      edges = data.products.edges;
      lastCursor = edges[edges.length - 1].cursor;
      setTimeout(() => {
        requestData(accessToken, GET_ALL_PRODUCTS, lastCursor);
      }, 1000);
    });
  });

  function requestData(token, queryName, cursor) {
    const variables = { after: cursor };
    console.log(cursor);
    const res = axios({
      headers: {
        'X-Shopify-Access-Token': token,
      },
      method: 'post',
      data: {
        query: queryName,
        variables: variables,
      },
      url: url,
    });

    return res;
  }

Solution

  • It seems that you need to implement some recursion to your code - like this:

      router.post('/getAllProducts', bodyParser(), async (ctx, next) => {
        let allProducts;
        const { accessToken } = ctx.session;
        ctx.response.status = 200;
    
        function loadData(cursor) {
          requestData(accessToken, GET_ALL_PRODUCTS, cursor).then((res) => {
            const data = res.data.data;
            // process data here, eg: allProducts = [...allProducts, ...data];
            const edges = data.products.edges;
            const nextCursor = edges.length ? edges[edges.length - 1].cursor : null;
            if (nextCursor) {
              setTimeout(() => {
                loadData(nextCursor);
              }, 1000);
            } else {
              // now we have all data
              sendToClient(allProducts);
            }
          });
        }
        loadData(null);
      });
    
      function requestData(token, queryName, cursor) {
        const variables = { after: cursor };
        console.log(cursor);
        const res = axios({
          headers: {
            'X-Shopify-Access-Token': token,
          },
          method: 'post',
          data: {
            query: queryName,
            variables: variables,
          },
          url: url,
        });
    
        return res;
      }