Paginating queries
The Eduflow API supports paginating lists of data through standard GraphQL connections.
Example
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 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": "Geoff@example.edu"
}
],
"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": "Geoff@example.edu"
}
],
"receivers": [
{
"email": null
}
]
}
}
]
}
}
}
}
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
}
}
}
}
}
}
}
Begins directly on the second page
hasPreviousPage
is nowtrue
New
endCursor
isYXJyYXljb25uZWN0aW9uOjM=
, 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": "Murphy@example.edu"
}
],
"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": "murphy@example.com"
}
],
"receivers": [
{
"email": null
}
]
}
}
]
}
}
}
}
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.
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": "murphy@example.edu"
}
],
"receivers": [
{
"email": "michael@example.edu"
}
]
}
}
]
}
}
}
}
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
last
item and travel backwardslast: 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
}
}
}
}
}
}
}
Returns 2 items
Last item
hasPreviousPage
istrue
startCursor
ofYXJyYXljb25uZWN0aW9uOjQ=
will be used inbefore
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": "nick@example.edu"
}
],
"receivers": [
{
"email": "michael@example.edu"
}
]
}
},
{
"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": "nick@example.edu"
}
],
"receivers": [
{
"email": null
}
]
}
}
]
}
}
}
}
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
}
}
}
}
}
}
}
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": "geoff@example.edu"
}
],
"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": "geoff@example.edu"
}
],
"receivers": [
{
"email": "nicholas@example.edu"
}
]
}
}
]
}
}
}
}
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'safter:
to start on next pagehasPreviousPage
hasNextPage
edges
List of containing node
s (list of objects) of the connection
node
The object itself, e.g. User
, Activity
See also
GraphQL Cursor Connections Specification on relay.dev (archive.org)
Pagination on graphql.org (archive.org)
Last updated