Bird
Raised Fist0
GraphQLquery~20 mins

Relay specification compliance in GraphQL - Practice Problems & Coding Challenges

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Challenge - 5 Problems
🎖️
Relay Mastery
Get all challenges correct to earn this badge!
Test your skills under time pressure!
query_result
intermediate
2:00remaining
What is the output of this Relay-compliant GraphQL query?
Given a GraphQL schema with a Node interface and a User type implementing it, what will be the output of this query fetching a user by ID with Relay's node field?
GraphQL
query {
  node(id: "VXNlcjox") {
    id
    ... on User {
      name
    }
  }
}
A{ "data": { "node": { "id": "VXNlcjox", "name": "Alice" } } }
B{ "data": { "node": { "id": "1", "name": "Alice" } } }
C{ "data": { "node": null } }
D{ "errors": [{ "message": "Field 'node' does not exist" }] }
Attempts:
2 left
💡 Hint
Remember that Relay encodes the global ID as a base64 string combining type and ID.
🧠 Conceptual
intermediate
1:30remaining
Which Relay specification rule ensures consistent pagination?
Which of the following Relay specification rules is responsible for consistent pagination behavior across different GraphQL connections?
AQueries must use fragments for all fields.
BEvery node must have a globally unique <code>id</code> field.
CAll connections must implement <code>edges</code> and <code>pageInfo</code> fields.
DMutations must return a <code>clientMutationId</code>.
Attempts:
2 left
💡 Hint
Think about how Relay handles lists and pagination.
📝 Syntax
advanced
2:00remaining
Which GraphQL fragment correctly implements Relay's Node interface?
Select the fragment that correctly queries a Relay Node with its global ID and typename.
GraphQL
fragment NodeFragment on Node {
  id
  __typename
}
Afragment NodeFragment on Node { id __type }
Bfragment NodeFragment on Node { id name }
Cfragment NodeFragment on Node { __id __typename }
Dfragment NodeFragment on Node { id __typename }
Attempts:
2 left
💡 Hint
Relay nodes always have an id and __typename.
optimization
advanced
2:30remaining
How to optimize Relay pagination queries to reduce overfetching?
Which approach best optimizes Relay pagination queries to avoid fetching unnecessary data?
AAlways fetch all edges without limits to avoid multiple queries.
BUse <code>first</code> or <code>last</code> arguments with a small number and request only needed fields in <code>edges.node</code>.
CInclude all possible fields in the <code>node</code> selection to prevent future queries.
DAvoid using <code>pageInfo</code> to reduce query size.
Attempts:
2 left
💡 Hint
Think about limiting data and selecting only what you need.
🔧 Debug
expert
3:00remaining
Why does this Relay mutation response cause a client error?
A Relay mutation returns this response: { "data": { "updateUser": { "user": { "id": "1", "name": "Bob" } } } } Why does Relay client report an error?
AThe <code>id</code> field is not a global ID encoded as base64.
BThe mutation response is missing <code>clientMutationId</code>.
CThe <code>user</code> field should be named <code>node</code>.
DThe response is missing the <code>edges</code> field.
Attempts:
2 left
💡 Hint
Relay expects global IDs in mutation responses.

Practice

(1/5)
1. What is the main purpose of the edges field in a Relay-compliant GraphQL connection?
easy
A. To store metadata about the entire list
B. To hold the list of items along with their cursors for pagination
C. To define the total count of items in the list
D. To specify the GraphQL schema version

Solution

  1. Step 1: Understand Relay connection structure

    Relay connections use edges to represent each item with its cursor for pagination.
  2. Step 2: Identify the role of edges

    The edges field contains nodes (items) and cursors, enabling smooth pagination.
  3. Final Answer:

    To hold the list of items along with their cursors for pagination -> Option B
  4. Quick Check:

    edges = items + cursors [OK]
Hint: Edges always pair items with cursors for pagination [OK]
Common Mistakes:
  • Confusing edges with pageInfo
  • Thinking edges store only items without cursors
  • Mixing edges with totalCount field
2. Which of the following is the correct syntax to request the first 5 items in a Relay connection named users?
easy
A. { users(first: 5) { edges { node { id } } } }
B. { users(limit: 5) { edges { node { id } } } }
C. { users(count: 5) { edges { node { id } } } }
D. { users(take: 5) { edges { node { id } } } }

Solution

  1. Step 1: Recall Relay pagination argument

    Relay uses first to specify how many items to fetch from the start.
  2. Step 2: Check syntax correctness

    Only first: 5 is valid; limit, count, and take are not Relay standard arguments.
  3. Final Answer:

    { users(first: 5) { edges { node { id } } } } -> Option A
  4. Quick Check:

    Use first for Relay pagination [OK]
Hint: Use 'first' to fetch initial items in Relay queries [OK]
Common Mistakes:
  • Using non-Relay arguments like limit or count
  • Omitting edges or node fields
  • Confusing Relay with REST query parameters
3. Given this GraphQL query on a Relay connection:
{ posts(first: 2) { edges { cursor node { title } } pageInfo { hasNextPage } } }

And the server returns:
{ "data": { "posts": { "edges": [ { "cursor": "cursor1", "node": { "title": "Post A" } }, { "cursor": "cursor2", "node": { "title": "Post B" } } ], "pageInfo": { "hasNextPage": true } } } }

What does hasNextPage indicate?
medium
A. The query failed to fetch posts
B. There are no more posts after the current 2
C. The current page is the last page
D. There are more posts available after the current 2

Solution

  1. Step 1: Understand pageInfo.hasNextPage

    This field tells if more items exist beyond the current page.
  2. Step 2: Interpret the returned value

    The value true means more posts exist after the fetched two.
  3. Final Answer:

    There are more posts available after the current 2 -> Option D
  4. Quick Check:

    hasNextPage = true means more data [OK]
Hint: True hasNextPage means more items exist [OK]
Common Mistakes:
  • Assuming true means no more data
  • Confusing hasNextPage with hasPreviousPage
  • Ignoring pageInfo in Relay connections
4. You wrote this Relay connection query:
{ comments(last: 3) { edges { node { text } } } }

But the server returns an error:
"Field 'last' is not supported on this connection"

What is the likely cause?
medium
A. The connection does not support backward pagination with 'last'
B. The 'last' argument must be replaced with 'first'
C. The query is missing the 'before' cursor argument
D. The 'edges' field is misspelled

Solution

  1. Step 1: Understand Relay pagination directions

    Relay supports forward pagination with first and backward with last.
  2. Step 2: Identify server limitation

    Some connections only support forward pagination; thus, last is unsupported.
  3. Final Answer:

    The connection does not support backward pagination with 'last' -> Option A
  4. Quick Check:

    Unsupported 'last' means no backward pagination [OK]
Hint: Check if connection supports 'last' for backward pagination [OK]
Common Mistakes:
  • Replacing 'last' with 'first' without cursor
  • Assuming 'edges' spelling causes error
  • Ignoring need for 'before' cursor with 'last'
5. You want to fetch a paginated list of products using Relay spec. You need to get the first 3 products, then fetch the next 3 after the last cursor. Which sequence of queries correctly follows Relay pagination?
hard
A. { products(last: 3) { edges { cursor node { name } } pageInfo { startCursor } } }
{ products(first: 3, after: "startCursor") { edges { node { name } } } }
B. { products(first: 3) { edges { cursor node { name } } pageInfo { endCursor } } }
{ products(last: 3, before: "endCursor") { edges { node { name } } } }
C. { products(first: 3) { edges { cursor node { name } } pageInfo { endCursor } } }
{ products(first: 3, after: "endCursor") { edges { node { name } } } }
D. { products(first: 3) { edges { cursor node { name } } pageInfo { endCursor } } }
{ products(first: 3, after: "cursor") { edges { node { name } } } }

Solution

  1. Step 1: Fetch first 3 products with 'first' and get endCursor

    The first query correctly fetches 3 products and retrieves endCursor for next page.
  2. Step 2: Use 'after' with endCursor to fetch next 3 products

    The second query uses after: "endCursor" to continue pagination forward.
  3. Final Answer:

    Correct sequence uses 'first' and 'after' with endCursor -> Option C
  4. Quick Check:

    Use endCursor with after for next page [OK]
Hint: Use endCursor with after to paginate forward [OK]
Common Mistakes:
  • Using last with before for forward pagination
  • Passing literal 'cursor' instead of actual endCursor value
  • Mixing startCursor with after argument