Paginating queries

The Eduflow API supports paginating lists of data through standard GraphQL connections.

Example

Page 1
Response
Page 2
Response
Page 3
Response
Page 1

first: 2 will pick the first 2 reviews from this Teacher review activity:

{
activity(id: "5572112e-66ad-45de-bd83-1332df79f51c") {
... on TeacherReviewActivity {
title
activityType
reviews(first: 2) {
pageInfo {
hasPreviousPage
hasNextPage
endCursor
}
edges {
node {
createdAt
modifiedAt
answers {
booleanAnswer
scaleAnswer
textAnswer
comment
scaleAnswerPercentage
}
givers {
email
}
receivers {
email
}
}
}
}
}
}
}
Response

Response includes requested data and endCursor of YXJyYXljb25uZWN0aW9uOjE=, which we'll use in Page 2:

{
"data": {
"activity": {
"title": "Flow 1 - Activity 5 - Teacher's Perspective",
"activityType": "TeacherReview",
"reviews": {
"pageInfo": {
"hasPreviousPage": false,
"hasNextPage": true,
"endCursor": "YXJyYXljb25uZWN0aW9uOjE="
},
"edges": [
{
"node": {
"createdAt": "2021-02-03T07:06:20.054270",
"modifiedAt": "2021-02-03T07:06:20.054275",
"answers": [
{
"booleanAnswer": null,
"scaleAnswer": null,
"textAnswer": "Some awesome answer for question \"Question of type Text\" (a17d3ff4-25ac-4f15-bfde-8422112cf072) However media expert mind everything key shake manage clear until yes much realize professor defense begin national to authority among government seek performance probably compare role something image Congress next tree receive western wait bed memory dark person boy population size whom road they none spring information husband health officer past marriage officer where one success idea contain top become he case eight cell through rich late manager data every economic increase billion central almost.",
"comment": null,
"scaleAnswerPercentage": null
},
{
"booleanAnswer": null,
"scaleAnswer": 1,
"textAnswer": null,
"comment": null,
"scaleAnswerPercentage": 25
},
{
"booleanAnswer": false,
"scaleAnswer": null,
"textAnswer": null,
"comment": "Yard consumer subject plant every than education life.",
"scaleAnswerPercentage": null
}
],
"givers": [
{
"email": "[email protected]"
}
],
"receivers": [
{
"email": null
}
]
}
},
{
"node": {
"createdAt": "2021-02-03T00:06:20.095326",
"modifiedAt": "2021-02-03T00:06:20.095335",
"answers": [
{
"booleanAnswer": null,
"scaleAnswer": null,
"textAnswer": "Some awesome answer for question \"Question of type Text\" (a17d3ff4-25ac-4f15-bfde-8422112cf072) Author easy herself treat budget majority recently theory onto argue foreign win situation shake sense certain opportunity coach picture family picture attack almost short should discover allow down while picture finish every tree watch across above consumer audience after building environmental look second identify live challenge edge establish why lawyer that white customer market idea our local when rich television still indeed seek investment ever attorney analysis why about major everybody culture expect what wonder.",
"comment": null,
"scaleAnswerPercentage": null
},
{
"booleanAnswer": null,
"scaleAnswer": 4,
"textAnswer": null,
"comment": null,
"scaleAnswerPercentage": 100
},
{
"booleanAnswer": true,
"scaleAnswer": null,
"textAnswer": null,
"comment": "In including wonder policy some piece scientist.",
"scaleAnswerPercentage": null
}
],
"givers": [
{
"email": "[email protected]"
}
],
"receivers": [
{
"email": null
}
]
}
}
]
}
}
}
}
Page 2

Pass the first page's endCursor into first:

{
activity(id: "5572112e-66ad-45de-bd83-1332df79f51c") {
... on TeacherReviewActivity {
title
activityType
reviews(first: 2, after: "YXJyYXljb25uZWN0aW9uOjE=") {
pageInfo {
hasPreviousPage
hasNextPage
endCursor
}
edges {
node {
createdAt
modifiedAt
answers {
booleanAnswer
scaleAnswer
textAnswer
comment
scaleAnswerPercentage
}
givers {
email
}
receivers {
email
}
}
}
}
}
}
}
Response
  • Begins directly on the second page

  • hasPreviousPage is now true

  • New endCursor is YXJyYXljb25uZWN0aW9uOjM=, let's use it on Page 3:

{
"data": {
"activity": {
"title": "Flow 1 - Activity 5 - Teacher's Perspective",
"activityType": "TeacherReview",
"reviews": {
"pageInfo": {
"hasPreviousPage": true,
"hasNextPage": true,
"endCursor": "YXJyYXljb25uZWN0aW9uOjM="
},
"edges": [
{
"node": {
"createdAt": "2021-02-03T09:12:20.137659",
"modifiedAt": "2021-02-03T09:12:20.137664",
"answers": [
{
"booleanAnswer": null,
"scaleAnswer": null,
"textAnswer": "Some awesome answer for question \"Question of type Text\" (a17d3ff4-25ac-4f15-bfde-8422112cf072) Be station board find own rest either agreement account report investment personal form information fall rise guess site local father attorney season argue call along Congress crime watch again watch decide method mean leader because plan decision audience tonight kitchen by box carry serve we look who realize focus check create newspaper next room either event every business box section cup feel father direction college difficult garden computer production should side decision force issue send challenge return debate force production half lawyer walk inside positive that beautiful allow response land.",
"comment": null,
"scaleAnswerPercentage": null
},
{
"booleanAnswer": null,
"scaleAnswer": 4,
"textAnswer": null,
"comment": null,
"scaleAnswerPercentage": 100
},
{
"booleanAnswer": true,
"scaleAnswer": null,
"textAnswer": null,
"comment": "Reflect leader understand another management.",
"scaleAnswerPercentage": null
}
],
"givers": [
{
"email": "[email protected]"
}
],
"receivers": [
{
"email": null
}
]
}
},
{
"node": {
"createdAt": "2021-02-03T00:06:20.179206",
"modifiedAt": "2021-02-03T00:06:20.179212",
"answers": [
{
"booleanAnswer": null,
"scaleAnswer": null,
"textAnswer": "Some awesome answer for question \"Question of type Text\" (a17d3ff4-25ac-4f15-bfde-8422112cf072) Feel artist star determine family trouble man enjoy turn medical list mouth itself together sense along than authority bag skin check simply heart assume issue by office though community read trial since success you TV worry your stuff security office provide oil push treatment area these early discussion even treatment general hope whole enjoy financial talk after health kitchen ready region area support meet next consumer federal street section traditional him garden crime anything ready thought western sometimes line chance nor anything can thing sense before available view us both attack lay show information form wind memory main program center rock value sense personal.",
"comment": null,
"scaleAnswerPercentage": null
},
{
"booleanAnswer": null,
"scaleAnswer": 4,
"textAnswer": null,
"comment": null,
"scaleAnswerPercentage": 100
},
{
"booleanAnswer": false,
"scaleAnswer": null,
"textAnswer": null,
"comment": "Five economic affect writer approach white.",
"scaleAnswerPercentage": null
}
],
"givers": [
{
"email": "[email protected]"
}
],
"receivers": [
{
"email": null
}
]
}
}
]
}
}
}
}
Page 3

This time, for variety, let's just take 1, and return different fields:

{
activity(id: "5572112e-66ad-45de-bd83-1332df79f51c") {
... on TeacherReviewActivity {
title
activityType
reviews(first: 1, after: "YXJyYXljb25uZWN0aW9uOjM=") {
pageInfo {
endCursor
}
edges {
node {
reviewType
createdAt
modifiedAt
answers {
scaleAnswerPercentage
}
givers {
email
}
receivers {
email
}
}
}
}
}
}
}

Based on the query being adjust to first: 1, we should only see one item returned in page 3.

Response
  • Only shows the fields requested (fields don't need to be the same each time)

  • Shows reviewType

  • Only shows 1 result, per first

{
"data": {
"activity": {
"title": "Flow 1 - Activity 5 - Teacher's Perspective",
"activityType": "TeacherReview",
"reviews": {
"pageInfo": {
"endCursor": "YXJyYXljb25uZWN0aW9uOjQ="
},
"edges": [
{
"node": {
"reviewType": "TeacherReview",
"createdAt": "2021-02-03T09:36:20.221437",
"modifiedAt": "2021-02-03T09:36:20.221441",
"answers": [
{
"scaleAnswerPercentage": null
},
{
"scaleAnswerPercentage": 125
},
{
"scaleAnswerPercentage": null
}
],
"givers": [
{
"email": "[email protected]"
}
],
"receivers": [
{
"email": "[email protected]"
}
]
}
}
]
}
}
}
}

The above example moves between 3 pages, passing the endCursor of the previous query into the after of the next page's. The initial (first) page doesn't need any after. The final page alters the fields queried and changes the amount returned.

Bonus: Start at last item and travel backwards

Page 1
Response
Page 2
Response
Page 1

last: 2 instead of first:

{
activity(id: "5572112e-66ad-45de-bd83-1332df79f51c") {
... on TeacherReviewActivity {
title
activityType
reviews(last: 2) {
pageInfo {
hasPreviousPage
hasNextPage
startCursor
}
edges {
node {
reviewType
createdAt
modifiedAt
answers {
scaleAnswerPercentage
}
givers {
email
}
receivers {
email
}
}
}
}
}
}
}
Response
  • Returns 2 items

  • Last item

  • hasPreviousPage is true

  • startCursor of YXJyYXljb25uZWN0aW9uOjQ= will be used in before on the next page

{
"data": {
"activity": {
"title": "Flow 1 - Activity 5 - Teacher's Perspective",
"activityType": "TeacherReview",
"reviews": {
"pageInfo": {
"hasPreviousPage": true,
"startCursor": "YXJyYXljb25uZWN0aW9uOjQ="
},
"edges": [
{
"node": {
"reviewType": "TeacherReview",
"createdAt": "2021-02-03T08:06:20.221437",
"modifiedAt": "2021-02-03T08:06:20.221441",
"answers": [
{
"scaleAnswerPercentage": null
},
{
"scaleAnswerPercentage": 125
},
{
"scaleAnswerPercentage": null
}
],
"givers": [
{
"email": "[email protected]"
}
],
"receivers": [
{
"email": "[email protected]"
}
]
}
},
{
"node": {
"reviewType": "TeacherReview",
"createdAt": "2021-02-03T08:06:20.261409",
"modifiedAt": "2021-02-03T08:06:20.261414",
"answers": [
{
"scaleAnswerPercentage": null
},
{
"scaleAnswerPercentage": 125
},
{
"scaleAnswerPercentage": null
}
],
"givers": [
{
"email": "[email protected]"
}
],
"receivers": [
{
"email": null
}
]
}
}
]
}
}
}
}
Page 2

Since we're moving backwards, we use before:

{
activity(id: "5572112e-66ad-45de-bd83-1332df79f51c") {
... on TeacherReviewActivity {
title
activityType
reviews(last: 2, before: "YXJyYXljb25uZWN0aW9uOjU=") {
pageInfo {
hasPreviousPage
startCursor
}
edges {
node {
reviewType
createdAt
modifiedAt
answers {
scaleAnswerPercentage
}
givers {
email
}
receivers {
email
}
}
}
}
}
}
}
Response

Continue with cursor

{
"data": {
"activity": {
"title": "Flow 1 - Activity 5 - Teacher's Perspective",
"activityType": "TeacherReview",
"reviews": {
"pageInfo": {
"hasPreviousPage": true,
"startCursor": "YXJyYXljb25uZWN0aW9uOjM="
},
"edges": [
{
"node": {
"reviewType": "TeacherReview",
"createdAt": "2021-02-03T07:06:20.179206",
"modifiedAt": "2021-02-03T07:06:20.179212",
"answers": [
{
"scaleAnswerPercentage": null
},
{
"scaleAnswerPercentage": 100
},
{
"scaleAnswerPercentage": null
}
],
"givers": [
{
"email": "[email protected]"
}
],
"receivers": [
{
"email": null
}
]
}
},
{
"node": {
"reviewType": "TeacherReview",
"createdAt": "2021-02-03T07:06:20.221437",
"modifiedAt": "2021-02-03T07:06:20.221441",
"answers": [
{
"scaleAnswerPercentage": null
},
{
"scaleAnswerPercentage": 125
},
{
"scaleAnswerPercentage": null
}
],
"givers": [
{
"email": "[email protected]"
}
],
"receivers": [
{
"email": "[email protected]"
}
]
}
}
]
}
}
}
}

GraphQL Terms

Term

Description

first

For slicing, fetch the items at the beginning

last

For slicing, beginning at last item

after

Accepts a cursor ID of where to continue paginating

cursor

ID of the cursor, in Eduflow, sometimes equal to pageInfo.endCursor

pageInfo

Structure containing cursor location, item count, previous/next page

  • startCursor

  • endCursor: Use this in the next page's after: to start on next page

  • hasPreviousPage

  • hasNextPage

edges

List of containing nodes (list of objects) of the connection

node

The object itself, e.g. User, Activity

See also