How GraphQL Schema Works

Learn how to effectively structure a GraphQL schema and create an API that developers will love to use.

We'll cover the following

Introduction

Now that you understand the basic pieces that make up a GraphQL schema, it is time to learn how to assemble them into something meaningful.

A good API design is not reliant on using a specific technology. Rather, it is reliant on how you want your end-user to interact with your service.

With that said, GraphQL does make it easier, in some respects, to create an intuitive and performant API.

What to aim for

A good API is one that makes it clear what you are doing and how you will do it. That is to say, that at any point in its use, you should be certain what the result will be and how to arrive at that point.

You do not want to create an API that frustrates your users with side effects or leaves the uncertainty on how they are meant to retrieve or manipulate data.

For the most part, the key to this is not how clever your code is. The key is how you express your API.

Naming

There are only two hard things in Computer Science: cache invalidation and naming things.

– Phil Karlton

People make sense of their environment through labeling. We collate our knowledge by assigning it some kind of label.

An API is no different, and what often makes an API intuitive is how it names its operations.

One of the easiest wins when it comes to good API naming is to be consistent in your naming patterns. Take the following example:

Query {
   getUsers: [Users]
   listPhotos: [Photos]
}

Although both make sense on an individual level, you end up with the scenario where developers are asking themselves:

What was it again? getThis or listThat?

At best, you end up with an error during development or need to check the schema, and at worst, you end up with a bug in production. Either way, it can be a frustrating experience.

Language is important, and API design is no exception to this. Keep your naming consistent, and users will thank you.

Be specific

Additionally, it is important to be specific when naming types, fields, and other names. There are several reasons why:

First, it provides additional context to an Object Type or field. Consider this example:

type Photo {
   id: ID!
   url: String!
} 

When you first write your schema, this seems fine. But as your codebase grows and features are added, you may run into trouble.

Let’s say your manager decides that we are adding a gallery section to the website. No problem! However, the Photo Object Type was previously storing user avatars. Should we store gallery photos in there as well now?

So, now you end up with something like this:

type Photo {
   id: ID!
   url: String!
}

type GalleryPhoto {
   id: ID!
   url: String!
   galleryCaption: String
}

This works, but it feels clumsy. Now we are left with a generic Photo type, which, in reality, is for users, and a specific GalleryPhoto type.

If we had thought ahead with our schema design, we would have created the schema like this:

type UserProfilePhoto {
   id: ID!
   url: String!
}

This is explicit, easy to reason with, and does not stop us from adding similar types down the line. It also saves us from doing frustrating depreciations of our types to write the schema in the way it should have been done to begin with.

In short, try not to share types too much. When you do, think about the potential side-effects.

Get hands-on with 1400+ tech skills courses.