19
GraphQL Design Pattern (1): Pagination & Summary
So I designed a schema for a common feature,
basically frontend needs to display two things:
- Summary of items
- 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
- ...
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!
}
And the frontend query:
query DisplayAnimal(
$animalTypes: [AnimalType!]!
$pagingOptions: PagingOptions!
) {
displayAnimals(animalTypes: $animalTypes) {
summary {
mammal
bird
fish
}
animals {
totalCount
paginate(pagingOptions: $pagingOptions) {
name
}
}
}
}
- The summary is hardcorded. If frontend needed a new kind of summary, the schema has to change.
- The
summary
property feels like a boilerplate to implement.
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!
}
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
}
}
}
}
- No need to implement
summary
resolver on backend, leading to lesser code. - The summary is no longer hardcoded, e.g. you can query total count of birds and fishes.
- Smaller schema, less noise.
GraphQL Alias is a powerful feature, thus remember to incorporate it when designing the schema.
Actually I wrote this for my workplace team. I decided to post it here because maybe others might find it helpful.
19