Crafting Superior APIs with Design Guidelines: Set Up For Success
7 min read
Building APIs – especially public-facing ones – is hard. There are a lot of decisions to be made, starting with the API concept (GraphQL, REST, etc.) to be used, infrastructure, and much more. But having this is just the foundation of your API, and you have to build a good API on top of it (whatever "good" means in your case). This is where an API design guideline can come into play.
This article is the first in a series of GraphQL-related articles. We will start with the importance of an API design guideline and how it could help you and your team to write a good API. It also should provide ideas on what to include in such a guideline.
This article won't cover the initially touched fundamental decisions (like REST vs. GraphQL) or the infrastructure it is running on. I'll proceed with GraphQL as an example because that is what we have chosen for our main API. This article is neither about implementations. It is about concepts and ideas.
API Design Guideline and Why It Is Important
What Is An API Design Guideline?
First of all, what is "API design"? API design refers to the process of creating the interface that allows different software applications to communicate and exchange data with each other. Good API design can involve creating a well-structured, intuitive, and easy-to-use interface that meets the needs of its users while also being scalable, secure, and reliable. Again, how you define a "good" API design is depending on your needs.
What about the term "guidelines"? Guidelines in general provide a set of best practices, conventions, and recommendations.
Bringing those definitions together: An API design guideline is a set of best practices, conventions, and recommendations for creating the interface that allows different software applications to communicate and exchange data with each other. These guidelines aim to promote good API design practices, ensure consistency, and improve the quality of the API.
GraphQL API Design Guideline On a High Level
Before diving into technicalities in your guideline, make sure to define the goals and non-goals of the guideline and how or by whom it will be updated. This helps to evolve the guideline and keep it focused. Speaking of keeping it focused: Make sure to get to the point and don't write lengthy documents. People won't read it or find the desired content otherwise.
You don't have to reinvent an API design guideline from scratch. You can stand on the shoulder of giants and get inspiration from other popular APIs (Shopify, GitHub) etc. There are even design guidelines or tutorials out there like Shopify GraqhQL Design Tutorial.
Make sure to include examples. Examples are easier to understand if you provide "dos" and "don'ts" – and highlight them accordingly. This is what an example could look like (from our naming conventions section):
Explain❌
type Publication {
# ...
# We have a field called metaHTML in the database
# but it has no meaning to consumers
metaHTML: String
}
✅
type Publication {
# ...
descriptionSEO: String
}
❌
type Address {
# How could the country look like? "GER", "Germany", "🇩🇪"? 🤔
country: String!
}
(✅)
type Address {
# Even this could mean ISO alpha-2 or alpha-3,
# but this could be clarified in a description.
countryCode: String!
}
A few additional ideas that might improve your guideline document:
use toggles to hide some secondary content
provide resources; where is the idea coming from?
a short intro for a section on why it is important
use examples from your domain
KISS (Keep It Short Simple) – nobody will read a book about your API
highlight important keywords
Impressions From Our Guideline
In this section, I will share a few impressions of our current GraphQL API design guideline. Maybe we will make it public at some point if we think it is good enough.
First of all, this is the table of contents of the current version of our GraphQL API design guide (yes, we use Notion 😜):
I won't go into detail here but here are some things that our guideline includes. I'll copy some pieces, rephrase others, or provide ideas on what the section could include. Copied parts are shown as a quote.
General Naming Convention
Naming is a hard task. When a thing is named and being consumed by a client, there is almost no going back without a breaking change. To avoid this, try to be specific and avoid abstract names.
Instead:
Choose field names based on what makes sense
Don’t be influenced by legacy APIs or what the field is called in the database (DB Schema ≠ GQL Schema)
Choose self-documenting names
Resources
Note: Here we are providing the examples that I provided in the previous section.
Node Interface
Types that represent entities that have a lifetime (and are usually stored in their own database table) should implement the
Node
interface.Example:
Explaininterface Node { id: ID! } type Post implements Node { id: ID! # ... }
Booleans
Booleans are almost always non-nullable. Only make them optional if there is actual meaning in being
null
as opposed tofalse
.If there are more states than two, consider using an
enum
instead.
Custom Scalars
When should you create custom scalars? Unnecessarily introducing custom scalars can make your live harder evolving the API because you'll more likely introduce breaking changes.
How should they be named? We use PascalCase.
Not use custom scalars for validation, e.g. first_Int_NotNull_min_1_max_20
.
Queries – Single Entities
use the singular entity name, e.g.
post
(don’t use HTTP verbs like ingetPost
)if multiple unique filters are required (e.g. by
id
andslug
) use a single query with inputs optional and throw an error if either no arguments or multiple provideduse an optional return value to denote a “not found” rather than returning an error; only if not finding something really is an error it should be modeled as such (see
me
in examples)
Queries – Multiple Entities
This section should answer questions such as:
How to name a query returning multiple entities?
How to deal with pagination? When should pagination be added?
How to deal with Filtering and Sorting?
Mutations
This is another bigger section in our document and I'll just provide some ideas:
Naming convention: e.g.
publishPost
vs.postPublish
We don't follow CRUD (Create, Read, Update, Delete), e.g.
createPost
,updatePost
etc. We use more business-specific names and more fine-granular mutations.How to name arguments and outputs?
What should you return? (Most often the whole entity, but that might not be the case for every mutation)
Reading Recommendations
These are the reading recommendations that we have listed in our guideline:
Docs, Blog Posts, etc.
Example Implementations
YouTube
Conclusion
In my opinion, an API design guideline is essential for a team with more than a few people to create and evolve an API that feels consistent, is easy to use, and maintainable.
Hopefully, this article gave you an idea of why an API design guideline is helpful and provided some ideas about what to include and how to write it.
Is there anything that you think is a must in an API guideline?