Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Create Semantic Nullability Blog Post#1775

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
twof wants to merge6 commits intographql:source
base:source
Choose a base branch
Loading
fromtwof:semantic-nullability-blog

Conversation

twof
Copy link

No description provided.

@vercelVercel
Copy link

vercelbot commentedSep 12, 2024

@twof is attempting to deploy a commit to theThe GraphQL Foundation Team onVercel.

A member of the Team first needs toauthorize it.

@vercelVercel
Copy link

vercelbot commentedSep 19, 2024
edited
Loading

The latest updates on your projects. Learn more aboutVercel for Git ↗︎

NameStatusPreviewCommentsUpdated (UTC)
graphql-github-io✅ Ready (Inspect)Visit Preview💬Add feedbackNov 8, 2024 10:20am

@leebyron
Copy link
Collaborator

Love it! Ship whenever you feel this is ready

@twoftwof marked this pull request as ready for reviewNovember 8, 2024 07:31
Copy link
Member

@benjiebenjie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Reads really well and a great introduction to the topic! I’ve included some suggested edits/typo fixes, and I wonder if we can make the final paragraph more actionable?


# Semantic Nullability

> This blog post is directed at application developers using GraphQL. If you are a library author, you should read the more detailed feature spec instead.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This should either be a link to said spec or a promise to deliver such (e.g. via follow up blog post)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

We don't really have a single place to point library authors to right now since we're "between implementations" - let's ask them to get involved?

Suggested change
>This blog post is directed at application developers using GraphQL. If you are a library author, youshould read the more detailed feature spec instead.
>This blog post is directed at application developers using GraphQL. If you are a library author,the[nullability working group](https://github.com/graphql/nullability-wg) would love to hear fromyou- file an issue or join a meeting!

name: String!
age: Int
posts: [Post]
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This example (and the previous one) should include a nullable field too, perhaps avatarUrl?


You should use the modified version of the schema when doing code generation for your frontend application.

Altering the error handling behavior of your client may be a breaking change if your schema has already adopted semantic nullability, so it's suggested that you select new error handling behavior for your client first. Read the documentation for your specific client for more information.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This first sentence is a little confusing (changing client error handling may be a breaking change so you should change client error handling first); could you reword it (e.g. first -> before adopting semantic nullability) or expand it? Also changing client error handling is a breaking change whether or not you’ve adopted semantic nullability, I think? Also it’s somewhat independent of it: you can use one without the other? Perhaps something less specific might work well.

Also most clients don’t have this yet (do they?), should we be surfacing something more actionable?

### Server migration
Once Semantic Nullability has been released, you will be able to start migrating by updating your service to use the most recent version of GraphQL.

This will open up the option to begin evolving your schema document by document. You can place the document directive `@SemanticNullability` at the top of a file to begin using the new nullability features in that file. The directive will not impact the interpretation of any other files in your schema.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
This will open up the option to begin evolving your schema document by document. You can place the document directive`@SemanticNullability` at the top of a file to begin using the new nullability features in that file. The directive will not impact the interpretation of any other files in your schema.
This will open up the option to begin evolving your schema document by document. You can place the document directive`@extendedNullability` at the top of a file to begin using the new nullability features in that file. The directive will not impact the interpretation of any other files in your schema.

Not 100% sure on which directive name we landed on, but@extendedNullability is used below

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Good catch! The capitalisation is off either way.

BoD reacted with thumbs up emoji
twofand others added4 commitsNovember 8, 2024 01:38
…-developers.mdxCo-authored-by: Benjie <benjie@jemjie.com>
…-developers.mdxCo-authored-by: Benjie <benjie@jemjie.com>
…-developers.mdxCo-authored-by: Benjie <benjie@jemjie.com>
…-developers.mdxCo-authored-by: Benoit 'BoD' Lubek <BoD@JRAF.org>
Copy link
Member

@benjiebenjie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I've included some minor clarity/formatting tweaks; I still wonder if we should add a call to action: how do people get started?


# Semantic Nullability

> This blog post is directed at application developers using GraphQL. If you are a library author, you should read the more detailed feature spec instead.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

We don't really have a single place to point library authors to right now since we're "between implementations" - let's ask them to get involved?

Suggested change
>This blog post is directed at application developers using GraphQL. If you are a library author, youshould read the more detailed feature spec instead.
>This blog post is directed at application developers using GraphQL. If you are a library author,the[nullability working group](https://github.com/graphql/nullability-wg) would love to hear fromyou- file an issue or join a meeting!

}
```

One thing to make clear: this is not like using a type system in a compiled language (TS, Swift, Kotlin) where the type system makes compile-time guarantees about behavior at runtime. Rather you can think of GraphQL's type system as a "runtime" type system. You can trust that `age` will be an `Int`, because at runtime, GraphQL will assert that it is a `Int`, and throw an error if it is not. All types effectively represent a typecast, or a type assertion.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Generally type casts are just trusted without verification; let's just go with "type assertion" alone.

Suggested change
One thing to make clear: this is not like using a type system in a compiled language (TS, Swift, Kotlin) where the type system makes compile-time guarantees about behavior at runtime. Rather you can think of GraphQL's type system as a "runtime" type system. You can trust that`age` will be an`Int`, because at runtime, GraphQL will assert that it is a`Int`, and throw an error if it is not. All types effectively represent atypecast, or atype assertion.
One thing to make clear: this is not like using a type system in a compiled language (TS, Swift, Kotlin) where the type system makes compile-time guarantees about behavior at runtime. Rather you can think of GraphQL's type system as a "runtime" type system. You can trust that`age` will be an`Int`, because at runtime, GraphQL will assert that it is a`Int`, and throw an error if it is not. All types effectively represent a type assertion.

Comment on lines +27 to +29
This results in `null` having two different meanings in GraphQL.
1. No value was provided. The `User` never provided an `age`.
2. There was an error resolving the field. The `User` provided an age in the form of a `Float` and it couldn't be cast to an `Int`, or our new `BirthdayBoy` provider [microservice](https://www.youtube.com/watch?v=y8OnoxKotPQ) timed out and never returned the `User`'s birthday.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Slight restructure; Markdown wants a newline here and it felt safer to explicitly call out the second sentence in each list item as an example.

Feel free to reject this, but please put a blank line just above the numbered list.

Suggested change
This results in`null` having two different meanings in GraphQL.
1. No value was provided. The`User` never provided an`age`.
2. There was an error resolving the field. The`User` provided an age in the form of a`Float` and it couldn't be cast to an`Int`, or our new`BirthdayBoy` provider[microservice](https://www.youtube.com/watch?v=y8OnoxKotPQ) timed out and never returned the`User`'s birthday.
This results in`null` having two different meanings in GraphQL:
1. no value was provided (e.g. the`User` never provided an`age`), or
2. there was an error resolving the field (e.g. the`User` provided an age in the form of a`Float` and it couldn't be cast to an`Int`, or our new`BirthdayBoy` provider[microservice](https://www.youtube.com/watch?v=y8OnoxKotPQ) timed out and never returned the`User`'s birthday).

Comment on lines +33 to +35
Returning to the GraphQL type system, we can see it has two options to indicate the nullability of a field.
1. `String` which we now know means the field can be a `String`, `null`, or `(Error, null)`
2. `String!` which we now know means the field can be `String`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
Returning to the GraphQL type system, we can see it has two options to indicate the nullability of a field.
1.`String` which we now know means the field can be a`String`,`null`, or`(Error, null)`
2.`String!` which we now know means the field can be`String`
Returning to the GraphQL type system, we can see it has two options to indicate the nullability of a field:
1.`String`, which we now know means the field can be a`String`,`null`, or`(Error, null)`; and
2.`String!`, which we now know means the field can be`String`.

1. `String` which we now know means the field can be a `String`, `null`, or `(Error, null)`
2. `String!` which we now know means the field can be `String`

When an error occurs resolving a `String` field, it's not much of a problem for clients. They can decide if they can deal with that field missing or not. However when an error occurs resolving a `String!` field, GraphQL responds by destroying part of the result data before it's sent to the client. Given the danger, many developers choose to never use any non-nullable fields.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I think you're meaning the server-side "don't make non-null fields available" idea, rather than the client-side "don't consume non-null fields".

Suggested change
When an error occurs resolving a`String` field, it's not much of a problem for clients. They can decide if they can deal with that field missing or not. However when an error occurs resolving a`String!` field, GraphQL responds by destroying part of the result data before it's sent to the client. Given the danger, many developers choose to neveruse anynon-nullable fields.
When an error occurs resolving a`String` field, it's not much of a problem for clients. They can decide if they can deal with that field missing or not. However when an error occurs resolving a`String!` field, GraphQL responds by destroying part of the result data before it's sent to the client. Given the danger, many developers choose to neveraddnon-nullable fields to the schema.


When an error occurs resolving a `String` field, it's not much of a problem for clients. They can decide if they can deal with that field missing or not. However when an error occurs resolving a `String!` field, GraphQL responds by destroying part of the result data before it's sent to the client. Given the danger, many developers choose to never use any non-nullable fields.

Every time developers are surveyed about their issues with GraphQL, they talk about nullability. The Nullability Working Group has been hard at work, and we believe we finally have a solution.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

We've had a number of solutions (including e.g. CCN); let's big up this one a little more:

Suggested change
Every time developers are surveyed about their issues with GraphQL, they talk about nullability. The Nullability Working Group has been hard at work, and we believe we finally have a solution.
Every time developers are surveyed about their issues with GraphQL, they talk about nullability. The Nullability Working Group has been hard at work, and we believe we finally have aworkablesolution that meets everyone's needs.


3. A field which can be `String` or `(Error, null)`

This is what we're calling "Semantic non-null". The syntax we've chosen is the following
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
This is what we're calling "Semantic non-null". The syntax we've chosen is the following
This is what we're calling "Semantic non-null". The syntax we're currently proposing is the following

| String | Semantic non-null |
| String! | Strict non-null |

Types are now semantic non-null by default. Question marks are used to indicate a nullable field similar to many other modern languages. `String!` retains its meaning. This is of course, a breaking change, and GraphQL prides itself in offering a path to non-breaking evolution for existing services. So alongside the new type, we're introducing some mechanics to assist developers in making incremental updates to their applications.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Rather than saying thisis a breaking change, let's say itwould be a breaking change and then we can clarify why it isn't.

Suggested change
Types are nowsemantic non-null by default. Question marks are used to indicate a nullable field similar to many other modern languages.`String!` retains its meaning. This is of course, a breaking change, and GraphQL prides itself in offering a path to non-breaking evolution for existing services. So alongside the new type, we're introducing some mechanics to assist developers in making incremental updates to their applications.
With this syntax, types becomesemantic non-null by default. Question marks(`?`)are used to indicate a nullable field similar to many other modern languages.`String!` retains its meaning.
This would be a breaking change; but GraphQL prides itself in offering a path to non-breaking evolution for existing services, so alongside the new type we're introducing some mechanics to assist developers in making incremental updates to their applications.

}
```

One thing to make clear: this is not like using a type system in a compiled language (TS, Swift, Kotlin) where the type system makes compile-time guarantees about behavior at runtime. Rather you can think of GraphQL's type system as a "runtime" type system. You can trust that `age` will be an `Int`, because at runtime, GraphQL will assert that it is a `Int`, and throw an error if it is not. All types effectively represent a typecast, or a type assertion.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

You can trust thatage will be anInt, because at runtime, GraphQL will assert that it is aInt, and throw an error if it is not.

age is nullable here, so it could benull as well, and won't throw for anull value. Maybename would be a better example?

1. `String` which we now know means the field can be a `String`, `null`, or `(Error, null)`
2. `String!` which we now know means the field can be `String`

When an error occurs resolving a `String` field, it's not much of a problem for clients. They can decide if they can deal with that field missing or not. However when an error occurs resolving a `String!` field, GraphQL responds by destroying part of the result data before it's sent to the client. Given the danger, many developers choose to never use any non-nullable fields.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

GraphQL responds by destroying part of the result data

destroying is quite a strong word. 🙂 Perhapsnullifying?

}
```

One thing to make clear: this is not like using a type system in a compiled language (TS, Swift, Kotlin) where the type system makes compile-time guarantees about behavior at runtime. Rather you can think of GraphQL's type system as a "runtime" type system. You can trust that `age` will be an `Int`, because at runtime, GraphQL will assert that it is a `Int`, and throw an error if it is not. All types effectively represent a typecast, or a type assertion.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
One thing to make clear: this is not like using a type system in a compiled language (TS, Swift, Kotlin) where the type system makes compile-time guarantees about behavior at runtime. Rather you can think of GraphQL's type system as a "runtime" type system. You can trust that`age` will be an`Int`, because at runtime, GraphQL will assert that it isa`Int`, and throw an error if it is not. All types effectively represent a typecast, or a type assertion.
One thing to make clear: this is not like using a type system in a compiled language (TS, Swift, Kotlin) where the type system makes compile-time guarantees about behavior at runtime. Rather you can think of GraphQL's type system as a "runtime" type system. You can trust that`age` will be an`Int`, because at runtime, GraphQL will assert that it isan`Int`, and throw an error if it is not. All types effectively represent a typecast, or a type assertion.

Comment on lines +33 to +35
Returning to the GraphQL type system, we can see it has two options to indicate the nullability of a field.
1. `String` which we now know means the field can be a `String`, `null`, or `(Error, null)`
2. `String!` which we now know means the field can be `String`

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

You switch here from talking about an Integer age field, to a String field? The same example should flow through.

Comment on lines +66 to +67
id: ID!
name: String!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Maybe a note that the!'s can be removed, especially for non-ID fields?


Because your client can decide how it handles errors, it will also be responsible for providing a modified version of the schema. For example, if the client raises an exception when an errored field is read, it can mark all "semantically non-null" fields as non-nullable in the schema provided to you as a frontend developer.

![Example code generation](https://i.imgur.com/i3hdCND.png)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Why isdogString and notString? on the RHS? It wouldn't become non-nullable because of the client library?

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

@benjiebenjiebenjie requested changes

@glen-84glen-84glen-84 requested changes

@BoDBoDAwaiting requested review from BoD

Assignees
No one assigned
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

6 participants
@twof@leebyron@benjie@glen-84@BoD@saihaj

[8]ページ先頭

©2009-2025 Movatter.jp