Having a properly designed GraphQL schema determines whether you’ll enjoy using GraphQL or start to question your life choices.
This is the guide I wish to have when designing my first GraphQL schema.
Who this guide is for
Front end developers, back end developers, mobile developers, doesn’t matter.
If you’re implementing a GraphQL server or consuming a GraphQL API, this guide is for you.
Having a database design or object oriented design experience is preferred since the knowledge is transferable.
Prerequisites
Basic knowledge of GraphQL and its syntax.
If you’re totally new to GraphQL, here’s a quick guide for you to get started:
Aside from that, having a basic understanding of SQL and Object Oriented Programming will help but not required.
Step 0: Always design based on product requirements
The ultimate goal of our GraphQL server is eventually to support running the business logic.
It is crucial to model our schema based on the product requirements to make development runs smoothly.
So the very first step you need to do is: talk to the product manager and understand the product or business requirements.
Step 1: Define the types
A typical software implementation will always have entities of some sort.
- In database design, entities are the tables.
- In object oriented design, entities are the classes.
- In GraphQL, entities are the types.
A good first step is to define the types used in the schema.
Here’s how a schema for a simple e-commerce app looks like:
Nullable or not?
Note that some fields end up with a !
which means that the field is mandatory or non-nullable.
In order to find out which types are nullable or non-nullable, we need to look at the requirements.
Let’s say in the example above, the product manager requested that the shop’s name and description are required, but the address field is optional.
Step 2: Define the queries and add missing relations
A query is an operation that retrieves data from the server.
It is the entry point of the GraphQL server to get the data that the client needs.
Think of it like a select statement in SQL, or a get method in OOP.
I’ll give some example of queries that are needed from the product perspective.
A user can see the detail of a product, its shop name and description
The query should look like this:
In order to support this operation, we need to add the missing pieces to our schema:
- A query to get the
product
by id - A way to get the shop from the
Product
type.
Note that the product(id: ID!)
query returns a nullable Product
not Product!
, because there’s no guarantee that the product will always exist.
As for the product’s shop
field, we mark it as non-nullable because a product must always have a shop based on the feature requirements.
A user can see the detail of another user and their shop if they have one
This is the query that we want to support:
Here are the missing pieces we need to add to our schema:
- A query to get the
User
by id - A way to get the shop from the
User
type.
A user can see the detail of a shop and its owner
This is the query that we want to support:
And this are the things we need to define in our schema:
A user can search for products within a shop with some filters applied
This is the query that we want to support:
To support this operation, we need to define the products
field in the Shop
type.
Note that the products
field can receive filter parameters.
This is similar to OOP where objects can define their own methods.
A user can search for products from any shop, with some filters applied. Show the shop name for each product.
Similar to the previous query, but we want to search for products from any shop.
We just need to add a new query for this since we already have the shop
field in the Product
type previously.
And so on…
I hope you get the point from the examples above.
After defining the types, add the queries you want to support and the missing relations required by the queries.
Step 3: Define the mutations
Mutations are operations that modify data on the server.
Think of it like an insert, update, or delete statement in SQL.
Some examples of mutations required in this project:
- Sign up a new user
- Create a new shop
- Add a new product to a shop
- Update a product’s stock
- Purchase a product
Now let’s define the mutations we want to support in our schema.
Wrapping up
This is the final schema that we designed based on the requirements, combining the types, queries, and mutations above.
The are a lot of details that I didn’t cover, such as pagination.
But this should give you a good starting point on designing your own GraphQL schema.
To summarize, the steps are:
- Define the types
- Define the queries and missing relations
- Define the mutations