Today marks the first release of the GraphQL spec ratified by the GraphQL Foundation. This is the culmination of three years of work, both technical and procedural. This is a proud moment and one worth celebrating.
What took so long?
The last ratified spec release was over three years ago, in June 2018. What took so long for this release? Certainly a worldwide pandemic didnʼt help our collective focus. But over the last few years there have been massive procedural improvements, most notably the formation of the GraphQL Foundation.
The June 2018 release was the last under the stewardship of Facebookʼs open source program. At the time, Facebook had unilateral control over the technology. This not only caused some legal teeth-gnashing but also had implications on who could contribute and how. While at Facebook I pushed to alleviate the legal concerns by moving GraphQL to MIT and OWFa licenses, however the single-company control was clearly hurting GraphQL adoption more than helping it. After I left Facebook in 2018 the contribution model was limiting my ability to run the project.
The GraphQL Foundation was charged with a mission to provide an open, neutral home for GraphQL and accelerate its development. It turns out this is easier said than done, and a colossal amount of work went into bootstrapping the foundation.
Does your company benefit from GraphQL?
Become a member and help us to sustain this mission!
Github accounts, domains, then trademark rights and other legal protections were transferred to the GraphQL Foundation. The GraphQL spec project joined the Joint Development Foundation which provided a legal framework for contributing to and using GraphQL while ensuring its neutral ownership. We established a technical steering committee (TSC) to democratize decisions. Onboarding onto this new contribution model had some growing pains, and we had to chase down new signed agreements from many past contributors. Weʼve since set up github bots to help automate everything.
While a great number of people helped get the GraphQL Foundation running and the spec project onto this new development model, Iʼd like to specifically thank Brian Warner, GraphQL Foundationʼs Program Manager, for his hard work and guidance.
What’s new in GraphQL 2021?
Since the June 2018 release, 35 contributors have made nearly 100 changes to the spec text ranging from minor clarifications to major changes.
Before I dig into those changes, it’s important to point out that as a user of GraphQL you’re actually unlikely to notice anything new in your day-to-day work. That’s because of a long-standing two-phase release process. Significant changes first go through an RFC Process which allows them to collect broad feedback and build consensus before being approved and merged by the spec editor into the working draft. After accumulating multiple changes, this working draft is later approved by GraphQL’s TSC as a ratified versioned release.
Nearly all GraphQL libraries and tools implement the working draft rather than the latest versioned release. This means quick access to each new capability as it is approved, including likely all of whatʼs new in this release.
That said, there are too many small improvements and clarifications to cover here so letʼs focus on a few significant changes worth highlighting:
Custom scalar specs
GraphQL has always defined a small set of “built in” scalars while offering the ability for services to define their own. However these custom scalars have often been at a disadvantage as tools donʼt always know what to do with them. Tool builders would love to offer better native behavior for the most common of these customer scalars, such as
URL, but need agreed upon rules.
At first, we considered defining those rules for a small handful of scalars directly into the GraphQL spec, but quickly ran into a problem. While conceptually simple, the details around something like dates are incredibly complex! A huge amount of variability and tradeoffs are found in existing standards like ISO-8601 or RFC-3339 and our working group struggled to agree on a GraphQL-specific set of rules. Worse still, we would have loved to introduce this type with the name “Date” or “DateTime” but found many existing services already using a custom scalar with these names and using different rules than we had agreed to. We absolutely did not want to break existing services.
We realized the typeʼs name didnʼt need to be the only way tools could identify a well known custom scalar! Instead a new directive was introduced:
@specifiedBy(url:). This allows a custom scalar to include a URL which describes its format so that tools can identify well known scalar specification URLs to imbue specific behavior. Now scalars with different names (i.e. Date or Time) can be interpreted as the same or many implementations of the same named scalar can have different interpretations (i.e. ISO-8601 or Unix timestamp). Most importantly these can be defined by anyone in the community.
For more information, read the initial proposal and spec contribution. Many contributed to this change, but specific thanks to Evan Huus, Andreas Marek and Matt Farmer for their direct championing of this change.
Repeatable & order significant directives
When we first introduced GraphQL, we knew it would be important to offer a way to extend the language. GraphQL directives allow tools across the ecosystem to add custom behavior to just about any aspect of the type system. Despite this, we made some assumptions that turned out to be too restrictive.
First, we originally required directives to be “unique per location”. The concern would be that a user might repeat a directive and tools might disagree on how to interpret this and do something unexpected or lose information. This was too restrictive for some cases, however simply removing the rule would still introduce the problem we sought to avoid. To solve for this, we now allow directives to individually opt-in by being marked as
Next, the spec did not explicitly state whether the order directives are found at a location is significant or not. Some implementations used unordered data structures internally to represent directives, which led to different interpretations of the same source. This too, it turned out was too restrictive for some cases where directives compose in a specific order. Now, it is clear that this order must be respected.
For more information, read the repeatable proposal and directive order proposal. A notable post-humous thank you to Oleg Ilyenko for championing this change and being an incredibly impactful contributor during GraphQLʼs early years.
GraphQL interfaces are a primary way of introducing heterogeneous data in a schema, describing the common set of fields available across a number of types which may appear in one spot. While type hierarchies can be quite complex and powerful in other languages, GraphQL favors simplicity over expressiveness and decided to restrict type hierarchies to a single level and not support inheritance. While this restriction has always been a bit contentious it mostly served schema authors well, save one common case: Connections.
GraphQL connections are a common convention for paginated data and when combined with interfaces can result in an overly restricted type system. Mike explores this problem and this solution in his fantastic deep dive blog post.
Now, interface hierarchies may be arbitrarily deep. However the desirable simplicity has been preserved by continuing to limit inheritance.
Removing parser ambiguity
GraphQL describes its language with a formal grammar, which should always produce exactly one interpretation given a GraphQL query. Grammar ambiguity is a problem faced by many languages and often sidestepped with a rule called greedy maximal munch. In practice, this rule isnʼt always enough to avoid the problem.
While GraphQL now does use a similar greedy rule, it also uses “lookahead restrictions” to not only avoid ambiguity in a more general way, but also provide more helpful messages in the case of syntax errors.
While our goal remains to evolve GraphQL as a stable base, there are currently nearly 20 open proposals at various stages of development. This includes improvements to error reporting and schema coordinates, nullability control in queries, broader Unicode support, input unions and tagged unions, investigations into broader covariance support, and more.
Notably, all of this work is being championed by community members via our RFC process who have all agreed to the collaboration rules established by JDF. All work takes place in open-invite meetings by the GraphQL Working Group. Not only to we keep meticulous notes (thanks primarily to Benjie Gillam) but also share videos of our meetings.
While we do our best to make it easy to follow long, if youʼre interested in contributing to GraphQL you are welcome to join our meetings or champion a proposal.
Again, if your organization benefits from GraphQL, please consider becoming a member and helping us to sustain the activities that support the health of our neutral ecosystem.