DEV Community

WJH
WJH

Posted on

GraphQL Design Pattern (1): Pagination & Summary

So I designed a schema for a common feature,
basically frontend needs to display two things:

  1. Summary of items
  2. The items

Suppose the page is about showing a list of
animals, and we want to show them the summary of
each type of animals.

FILTERS
[ ] Mammal (200)
[x] Birds (110)
[ ] Fish (200)

ITEMS
- Eagle
- Pigeon
- Stork
- ...
Enter fullscreen mode Exit fullscreen mode

Initial Design

Initially, the schema I designed is as follows:

query {
  displayAnimals(animalTypes: [AnimalType!]!): DisplayAnimalsResult!
}

enum AnimalType {
  MAMMAL
  BIRD
  FISH
}

type DisplayAnimalsResult {
  summary: DisplayAnimalsResultSummary!
  animals: FilteredAnimals!
}

type DisplayAnimalsResultSummary {
  mammal: Int!
  bird: Int!
  fish: Int!
}

type FilteredAnimals {
  totalCount: Int!  
  paginate(pagingOptions: PagingOptions!): [Animal!]!
}

type PagingOptions {
  currentPage: Int!
  itemsPerPage: Int!
}

type Animal {
  name: String!
}
Enter fullscreen mode Exit fullscreen mode

And the frontend query:

query DisplayAnimal(
  $animalTypes: [AnimalType!]!
  $pagingOptions: PagingOptions!
) {
  displayAnimals(animalTypes: $animalTypes) {
    summary {
      mammal
      bird
      fish
    }
    animals {
      totalCount
      paginate(pagingOptions: $pagingOptions) {
        name
      }
    } 
  }
}
Enter fullscreen mode Exit fullscreen mode

The Problem

  1. The summary is hardcorded. If frontend needed a new kind of summary, the schema has to change.
  2. The summary property feels like a boilerplate to implement.

A Better Design

After seeing this pattern over and over and getting
frustrated, I suddenly realised that the summary
property is actually not needed!

Let's see the new schema (note that DisplayAnimalsResult and DisplayAnimalsResultSummary are gone):

query {
  displayAnimals(animalTypes: [AnimalType!]!): FilteredAnimals!
}

enum AnimalType {
  MAMMAL
  BIRD
  FISH
}

type FilteredAnimals {
  totalCount: Int!  
  paginate(pagingOptions: PagingOptions!): [Animal!]!
}

type PagingOptions {
  currentPage: Int!
  itemsPerPage: Int!
}

type Animal {
  name: String!
}
Enter fullscreen mode Exit fullscreen mode

And the frontend query (here's the magic, using
GraphQL Property Alias):

query DisplayAnimal(
  $animalTypes: [AnimalType!]!
  $pagingOptions: PagingOptions!
) {
  mammal: displayAnimals(animalTypes: [MAMMAL]) {
    totalCount
  }
  bird: displayAnimals(animalTypes: [BIRD]) {
    totalCount
  }
  fish: displayAnimals(animalTypes: [FISH]) {
    totalCount
  }
  displayAnimals(animalTypes: $animalTypes) {
    animals {
      totalCount
      paginate(pagingOptions: $pagingOptions) {
        name
      }
    } 
  }
}
Enter fullscreen mode Exit fullscreen mode

How is this better?

  1. No need to implement summary resolver on backend, leading to lesser code.
  2. The summary is no longer hardcoded, e.g. you can query total count of birds and fishes.
  3. Smaller schema, less noise.

Conclusion

GraphQL Alias is a powerful feature, thus remember to incorporate it when designing the schema.

P/S

Actually I wrote this for my workplace team. I decided to post it here because maybe others might find it helpful.

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Immerse yourself in a wealth of knowledge with this piece, supported by the inclusive DEV Community—every developer, no matter where they are in their journey, is invited to contribute to our collective wisdom.

A simple “thank you” goes a long way—express your gratitude below in the comments!

Gathering insights enriches our journey on DEV and fortifies our community ties. Did you find this article valuable? Taking a moment to thank the author can have a significant impact.

Okay