GraphQL Pagination Basics

Introduction

Welcome to another GraphQL lesson that now focuses on pagination, a critical concept for handling large datasets efficiently.

Pagination is the technique of dividing a dataset into discrete pages, allowing clients to request data in manageable chunks instead of all at once. This improves performance, reduces bandwidth, and provides a better user experience.

Defining the GraphQL Schema with Pagination

First, let's define the Ruby code for the GraphQL schema using graphql-ruby:

Ruby
require 'sinatra'
require 'graphql'

class BookType < GraphQL::Schema::Object
  field :id, ID, null: false
  field :title, String, null: false
  field :author, String, null: false
end

class QueryType < GraphQL::Schema::Object
  field :books, [BookType], null: false do
    argument :limit, Integer, required: false
    argument :offset, Integer, required: false
  end
end

Here:

  • BookType class: It defines three fields: id, title, and author, all marked as non-nullable.
  • QueryType class: The books field takes two optional arguments: limit and offset, returning an array of BookType.

Implementing Resolvers with Pagination Logic

Resolvers are methods that handle fetching data when a field is queried. Here's how to add the pagination logic:

Ruby
BOOKS = Array.new(50) do |i|
  {
    id: (i + 1).to_s,
    title: "Book #{i + 1}",
    author: "Author #{i + 1}"
  }
end

class QueryType < GraphQL::Schema::Object
  field :books, [BookType], null: false do
    argument :limit, Integer, required: false
    argument :offset, Integer, required: false
  end

  def books(limit: 10, offset: 0)
    BOOKS[offset, limit] || []
  end
end

class MySchema < GraphQL::Schema
  query QueryType
end

Here:

  • BOOKS array: An array of 50 sample book objects is created for demonstration purposes using Ruby's Array.new method.
  • books resolver method: The resolver method takes two optional keyword arguments, limit and offset, with default values of 10 and 0, respectively.
  • Array slicing: The resolver uses Ruby's array slicing syntax BOOKS[offset, limit] to return a portion of the array. This takes the starting index (offset) and the number of elements to return (limit), effectively returning a subset of books based on the specified parameters, allowing for paginated results.

Fetching Paginated Data from the Client

We will make client-side requests to fetch paginated data using Ruby's Net::HTTP library. Here is how we can make paginated queries:

First, we define the query:

Ruby
require 'net/http'
require 'json'

query = <<~GRAPHQL
  query getBooks($limit: Int, $offset: Int) {
    books(limit: $limit, offset: $offset) {
      id
      title
      author
    }
  }
GRAPHQL

Then, we define our pagination variables and fetch the data:

Ruby
uri = URI('http://localhost:4000/graphql')

variables = {
  limit: 5,
  offset: 0
}

request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = JSON.generate({
  query: query,
  variables: variables
})

begin
  response = Net::HTTP.start(uri.hostname, uri.port) do |http|
    http.request(request)
  end
  
  data = JSON.parse(response.body)
  puts JSON.pretty_generate(data)
rescue StandardError => e
  puts "Error: #{e.message}"
end

Let's quickly understand how it works:

  • We define a GraphQL query, getBooks, that takes limit and offset as parameters to fetch a specific range of books.
  • We define the GraphQL URI and variables — the parameters limit and offset to control pagination.
  • We create a POST request using Net::HTTP::Post and set the appropriate headers.
  • We use JSON.generate to convert the query and variables into a JSON string for the request body.
  • We send the request using Net::HTTP.start and handle the response.
  • The response is parsed from JSON format and then printed to the console in a readable format.
  • We use begin/rescue to handle any errors that might occur during the request.

Lesson Summary

You've now learned:

  • What pagination is: Dividing data into discrete pages for performance and user experience.
  • GraphQL basics: Creating a schema and implementing resolvers with graphql-ruby and Sinatra.
  • Running and querying: Starting the Sinatra server and fetching paginated data from the client.

Next, you'll practice these concepts through exercises. Try adjusting the limit and offset values to get different sets of data. Congratulations on completing the lesson! The skills you've learned are valuable for creating efficient and flexible APIs using GraphQL. Well done!

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal