[GraphQL API] pageInfo endCursor does not match edge cursor?

Hi all!

I’m wondering if someone could clarify something around pagination for me. I noticed that if results are paginated, the pageInfo.endCursor doesn’t seem to match any of the actual edge’s cursor values? Here’s an example query

{
  viewer {
    starredRepositories(first: 5, orderBy: {field: STARRED_AT, direction: ASC}) {
      totalCount
      edges {
        cursor
      }
      pageInfo {
        endCursor
        hasNextPage
      }
    }
  }
}

This gives me something like this:

{
  "data": {
    "viewer": {
      "starredRepositories": {
        "totalCount": 1355,
        "edges": [
          {
            "cursor": "Y3Vyc29yOnYyOpLOTbQrt84AdYpN",
            "node": {
              "nameWithOwner": "pusher/libPusher"
            }
          },
          {
            "cursor": "Y3Vyc29yOnYyOpLOTcAKXc4AdYpQ",
            "node": {
              "nameWithOwner": "aaronbrethorst/BCCollectionView"
            }
          },
          {
            "cursor": "Y3Vyc29yOnYyOpLOTedfOc4AdYpS",
            "node": {
              "nameWithOwner": "domhofmann/PRTween"
            }
          },
          {
            "cursor": "Y3Vyc29yOnYyOpLOTe6u4M4AdYpT",
            "node": {
              "nameWithOwner": "laravel/laravel"
            }
          },
          {
            "cursor": "Y3Vyc29yOnYyOpLOUV_0xc4Atox4",
            "node": {
              "nameWithOwner": "jakiestfu/Snap.js"
            }
          }
        ],
        "pageInfo": {
          "endCursor": "Y3Vyc29yOnYyOpK5MjAxMy0wNC0wNlQxMDoxMToxNy0wNDowMM4Atox4",
          "hasNextPage": true
        }
      }
    }
  }
}

Why doesn’t pageInfo.endCursor equal Y3Vyc29yOnYyOpLOUV_0xc4Atox4? Are endCursors generated in some different way?

You may be asking: Why do you care? Just use the endCursor to fetch the results. You’re right! It does work, but I have a bit of an interesting case in my app. 

My app fetches all a user’s starred repositories in descending (aka most recently starred) order, and stores the results in IndexedDB. On page load, it first checks to see if hasNextPage is true or not, and if it is, is goes out and fetches any remaining stars. This has to happen in case the user abandons the page in the middle of the pages of stars getting fetched.

Once all those are fetched, it’s time to check if there’s any newer stars we may not have fetched yet — so my strategy was to flip the order from DESC to ASC , and use the cursor field of the first edge for the after filter. Unfortunately this is where I noticed using edge cursors resulted in a query failure! That’s why I’m inquiring what the difference is between  pageInfo.endCursor values and edge cursor values.

Thank you in advance!

Cursors are opaque and base64 encoded and sometimes you can find something useful from them. While your edge cursors contains something like “cursor:v2:Q_x”, endCursor contains “cursor:v2:2013-04-06T10:11:17-04:00x”. 

As you’re ordering by a field which is time then I’d say that’s a way they implemented this pageInfo(maybe query optimisation, dunno). It does sound a bit weird indeed as if you remove orderBy then last edges cursor is same as endCursor. Sound like endCursor in that case is designed to work like documented for a user to paginate forward and backwards without changing query, not like you do when trying to flip things around and change to a new query.

1 Like