Skip to content

Instantly share code, notes, and snippets.

@twof
Last active February 5, 2025 18:12
Show Gist options
  • Save twof/e0f9bb95a97d0c5f1b74fca58b3133cd to your computer and use it in GitHub Desktop.
Save twof/e0f9bb95a97d0c5f1b74fca58b3133cd to your computer and use it in GitHub Desktop.

Decision Document and FAQ

SN is a strange solution if we were starting from scratch, but given the requirements, it makes sense.

Requirements

  1. We cannot make breaking changes to GraphQL
    1. Developers must be able to evolve their services without doing full rewrites
  2. We must continue to support both advanced clients (Relay, Apollo, etc) and simple clients (curl, etc)
  3. Some GraphQL clients use caches
    1. Data produced by GraphQL services has to be trustworthy, so apps can trust the data in their caches
  4. In addition to existing GraphQL services, we must also cater to future GraphQL services
    1. (Editorial) I think GraphQL has a bright future, and therefor the future GraphQL services will greatly outweigh the current GraphQL services

FAQ

Why did CCN fail?

CCN failed due to a conflict between requirements 2 and 3. Simple clients frequently check for the existence of any errors, and if they find any, they throw out the entire response. Relay actually did the same thing more or less. Errors were reported to components and results were not cached. Because of null propagation, they couldn't trust that fields were truly null, or if they were null as the result of an error. As a result, they said they would basically apply nullable designators (?) to every field to prevent null propagation, and then continue to use their own directives.

On top of that, Relay makes heavy use of fragments. We never had a good way to resolve the issue of the same field in one fragment using a CCN designator while another fragment did not. Fragment modularity was floated as a proposal, but wasn't really pushed forward.

Additionally, no one was happy with the error handling story.

During discussions, we recognized that

  1. Null propagation wasn't desirable in most cases.
  2. GraphQL couldn't be treated like a programming language. Types act more like type assertions than what people might be familiar with from a language like C++.
  3. Therefor there was a hole in the type system. Every field could be Type, null, or (null + Error) by default, as opposed to programming languages where Type and null are the two possible values.

CCN felt more and more like it was papering over more fundamental problems as discussions continued, so CCN was sunsetted and replaced by Semantic Nullability.

Why Semantic Nullability

When CCN started to fall apart, we began asking fundamental questions, like if we started GQL today, would we introduce null propagation? Those discussion drove a few folks to put together new proposals about how we could solve the nullability problem from the schema-side rather than from the client-side.

SN is really two features that are getting bundled together.

First the new nullability syntax.

  1. A service should be able to indicate to clients that under normal circumstances, a field is not expected to be null.
  2. The solution should work for both advanced and simple clients (requirement 2).
  3. Indicating non-nullability under normal circumstances should not also introduce the risk of response destruction.

Second the "do not propagate null" flag.

  1. See requirement 3.
  2. There was clear desire to turn off null propagation entirely, even when a service wasn't using the new nullability syntax both to preserve cache integrity and in general.

How did we land on the selected syntax?

The short answer is that we voted on it.[1]

That said, I'll talk about why I personally voted for the winner. While one of the other options provided a better story for existing schema evolution, my focus was on requirement 4. The working group generally agrees that most fields should be semantically non-nullable under the new type system. I believe the most common type should be unadorned. While GraphQL is not a programming language, this additionally brings the nullability syntax more in line with other existing programming languages like Typescript, Kotlin, and Swift.

Furthermore, I see a future where a flag is introduced that makes schemas interpreted as Semantically Nullable by default, and the document directive will no longer have to be used. I imagine any new services will want to use that flag.

[1] Technically we voted to end discussion on syntax and use the selected syntax in our implementation and spec edits. In the end, moving to stage 2 will require consensus from the working group.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment