Since GraphQL's inception at Facebook four years ago, and its public release one year ago, the GraphQL community has been growing rapidly. More and more businesses, including large companies and tech giants, are adopting the technology.
GraphQL's evolution has taught its developers a lot about what's important when designing APIs. Here are a few best practices that they've come up with for GraphQL users and language designers, and a list of general principles for any software developer to follow when building a new product.
Naming matters. As soon as a client starts to make use of a field, it becomes much harder to change the name that they're using. Names should be obvious and self-documenting for the benefit of newcomers to the code base, and flexible enough to accommodate future versions of your product.
Think in graphs, not endpoints. Unlike traditional APIs, GraphQL exposes all of the data from a single endpoint. Your objective with GraphQL should be to create a unified, cohesive graph that allows users of your API to create subsets of that graph in order to build new product experiences. For example, by treating a search as an object, you might have that search object point to other search objects in order to suggest related searches to the end user.
Describe the data, not the view. Make sure that your API isn't linked too closely with the demands of your initial interface. If you're building an API for an iOS app, you might later port it to other devices such as desktop computers or feature phones. When building queries, focus on the underlying data, rather than how it's represented in your application.
GraphQL is a thin interface. GraphQL is intended to sit atop your existing and future systems. What it's not intended to do are things like authentication, authorization, caching, database query and optimization. By handling these concerns below the GraphQL service layer, your application becomes more resilient as your platform evolves and as you migrate between different services.
Hide implementation details. While GraphQL should be thin, it should also be a seam between your data and the details of its storage and retrieval. If you're giving away too much data in a single response, then some client might use the extra information for its own purposes, which results in their code base breaking when the implementation changes behind the scenes.
Principles and Lessons
Solve a real problem. For GraphQL, the problem was getting the data needed for the Facebook news feed on iOS devices over poor mobile network connections. This was an extremely pressing issue for Facebook as more and more daily users accessed the service on mobile devices. Identifying the real problem helps keep you grounded about which features to prioritize.
Think like the client. The topmost priorities of GraphQL's developers were the needs of the end user. Figure out who will be using the technology and what they want to accomplish. Just because there are existing practices or tools out there doesn't mean that they're the best solution for your particular problem.
Have a first client. Whenever you design something new, it's easy to start considering all the possible future use cases and accommodate them all up front. However, even the best predictions can go wrong and result in poor tradeoffs and unnecessary complexity. GraphQL's first client was the Facebook news feed for iOS, and those needs and priorities drove how it was initially designed.
Incremental adoption. Make it easy for your first client to replace their endpoints, resources or data models one by one. This allows them to try out new ideas and to evaluate the strengths and weaknesses of your product during the adoption process, instead of migrating to the whole thing immediately.
YAGNI (You Aren't Gonna Need It). Avoid implementing things that you might need in the future in favor of things that you definitely need today. When you consider adding a feature, ask yourself if it can be accomplished with the tools and features that you already have. Evaluate if the disadvantages of your existing system are preferable to the cost of developing a new feature.
Avoid "second system syndrome." Fred Brooks talks about this in his classic software engineer book "The Mythical Man-Month." The risk is that when you build a new thing for the second time, you'll feel less cautious and more experienced, and end up over designing the whole thing. The best way to combat this is to have someone who can play devil's advocate for you and provide a second opinion.
Timing is critical; recognize inflection points. Making changes to your product is easier at the beginning when you're working closely with your first client. Once it sees wider adoption, it becomes significantly harder to change. Consider making your code base open-source only when your product is older and needs less freedom to rapidly evolve.
Encourage taking measured risks. When you're solving an important problem, it's easy to be risk-averse and stick to what you know. However, managers and teams should be able to trust experienced engineers to decide when certain risks are worth taking and to be accountable for those decisions. If your strongest engineers are telling you that it's time for something new, give their thoughts a listen.