7 Best Practices to Design Cutting-Edge GraphQL Schemas

Photo by @medbadrc on Unsplash

Photo by @medbadrc on Unsplash

GraphQL is a relatively new technology brought to the world by Meta (formerly Facebook). Despite being new, it is getting more and more popular.

Almost all the big industries and many small organizations and startups use GraphQL. That’s why it is required knowledge for every web developer in today's age.

While working with GraphQL schemas, we must follow some best practices for designing cutting-edge schemas. Otherwise, as the project grows, there will be no smooth design, and the project will be a mess.

Today, we will discuss some best practices while designing GraphQL schemas. So, without further-a-do, let’s jump into the main points.

1. Use deprecation messages properly.

While working on a team, there are many scenarios when the requirements change. Sometimes, we need to change the field name or remove some fields.

For example, suppose you are building a blogging website. You are designing a schema for fetching a blog. The schema initially looks like the following schema:

blog(id: $id) {
	title
	subtitle
	imageUrl
}

Now, the requirement has changed, and you are told to include alt text for the images; now, you design the schema like the below:

blog(id: $id) {
	title
	subtitle
	image {
		src
		alt
	}
}

You now changed your API and published it to production.

But, Wait!

As soon as you publish your new changes to the production, your app will break because your front-end team has not implemented your changes yet! Even if you are implementing a public or partner API, it’s a BIG NO to push these changes directly!

On the contrary, keeping this field also doesn’t solve the problem because it is a redundant field. Your frontend team or end user might not know whether this field will be removed or not. You also don’t know for how long you will keep this field.

Keeping the field in this example might not be a big issue, but there might be lots of areas that should be removed at some point.

So what’s the Solution?

Instead of obliterating the field, deprecate the field with a reason and a date when you will remove this field. In this way, the frontend developers will have a chance to look into this issue, and they can change this field at some point.

type Blog {
	title: String
	subtitle: String
	imageUrl: String @deprecated(reason: "This field is deprecated and will be removed on Aug 6, 2022. Use `image` field instead.")
	image: {
		src: String
		alt: String
	}
}

2. Explicitly name your variables.

It would help if you named your schema variables explicitly. The variable's name should be concise and return the output it promised. Also, your variable naming should not mansplain its purpose or type.

Here are some examples of naming variables while designing GraphQL schema:

BAD

imageUrlString
descriptionText

GOOD

imageUrl
likesCount

In this example, if you pass an image URL with your variable, you should name it imageURL. On the other hand, if you are giving an image object with width, height, src, and alt text, you should call that variable image.

Similar applies to the likesCount too. likesCount means that we are passing the number of likes in this variable, but if we picked likes as our naming, it would mean the list of users who liked the post.

So, name your variables explicitly.

3. Use aliases.

Using aliases can solve a lot of redundancy problems. Let’s check the following example for a better understanding.

Let’s say we need to return two different types of descriptions for our schema. One is the description, and the other is the descriptionHtml. We can add these two same kinds of fields using aliases.

{
	description
	descriptionHtml: description(format: "HTML")
}

This is so powerful that we can use this in many use cases like below:

{
	descriptionEn: description(lang: "en")
	descriptionEnHTML: description(format: "HTML", lang: "en")
	descriptionFr: description(lang: "fr")
}

4. Make fields nullable.

It is another essential but easy practice you can consider while developing your every GraphQL project. It’s easy because GraphQL, by default, makes the fields nullable.

Making fields nullable is helpful because we might deprecate a field whenever the project requirement changes and stop assigning values to that variable.

This would throw an error if we didn’t make the field nullable. So, it is a great idea to keep the fields nullable unless you should make them non-nullable.

5. Use Relay Cursor Connection Specification while using pagination.

I have written an article explaining why we need to implement the Relay Cursor Connections Specification in GraphQL and how we can achieve this in Nest JS. You can read these two articles if you want. Best Practices to Work with GraphQL Pagination Never Hassle Again Working with GraphQL Paginationjavascript.plainenglish.io Implement Relay Cursor Connections Specification in NestJS with GraphQL Relay *Easy and simple steps to implement GraphQL Relay-Cursor-based pagination in NestJS.*javascript.plainenglish.io

6. Create a user entry point for the authenticated user.

Don’t allow the client applications to provide the user identity. Use authentication token to fetch user data. Also, create a user entry point to get the authenticated user's information.

BAD

user(email: $email) {
	username
	email
	name
	lastLoggedIn
}

GOOD

me {
	username
	email
	name
	lastLoggedIn
}

Also, remember, don’t ever save your authentication token in cookies or local storage. I wrote an article describing the best way to store authentication tokens in JavaScript. You can read this article if you want. The Ultimate Way to Store Authentication Tokens in JavaScript Handle authentication like a projavascript.plainenglish.io

7. Turn introspection off in production.

It is one of the most crucial things. Turn off the introspection of the GraphQL server while in production. You don’t want to expose your API design to the public unless you build the API for public apps.

That’s it. I hope this article will be helpful to you. Have a great day!

References