GraphQL Design Pattern (1): Pagination & Summary
Tags: graphql, schema, alias, pattern
Published: 2021-06-29 06:35:41

---
title: GraphQL Design Pattern (1): Pagination & Summary
published: true
description: 
tags: graphql, schema, alias, pattern
//cover_image: https://direct_url_to_image.jpg
---

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
- ...
```

## Initial Design

Initially, the schema I designed is as follows:
```graphql
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:
```graphql
query DisplayAnimal(
  $animalTypes: [AnimalType!]!
  $pagingOptions: PagingOptions!
) {
  displayAnimals(animalTypes: $animalTypes) {
    summary {
      mammal
      bird
      fish
    }
    animals {
      totalCount
      paginate(pagingOptions: $pagingOptions) {
        name
      }
    } 
  }
}
```

## 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):
```graphql
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](
https://graphqlmastery.com/blog/how-to-use-graphql-aliases)):
```graphql
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
      }
    } 
  }
}
```

## 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.