Skip to content

Commit

Permalink
Deprecate @nonnull (#6152)
Browse files Browse the repository at this point in the history
* Deprecate `@nonnull`

* more correct

* import the nullability directive

* update test fixtures
  • Loading branch information
martinbonnin authored Sep 18, 2024
1 parent 0508dd8 commit 8e14023
Show file tree
Hide file tree
Showing 14 changed files with 76 additions and 12 deletions.
43 changes: 40 additions & 3 deletions docs/source/advanced/nullability.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,43 @@ In order to change that default to "opt-in the errors you want to handle", you c
1. import the nullability directives.
1. Default to coercing to null: `extend schema @catchByDefault(to: NULL)`. This is a no-op to start exploring the directives.
1. Add `@catch` to individual fields, get more comfortable with how it works.
1. When ready to do the big switch, change to `extend schema catch(to: THROW)` and (at the same time) add `query GetFoo @catch(to: NULL) {}` on all operations/fragments (this is a no-op).
1. From this moment on, new queries written are `catch(to: THROW)` by default.
1. Remove `query GetFoo @catch(to: NULL) {}` progressively.
1. When ready to do the big switch, change to `extend schema catchByDefault(to: THROW)` and (at the same time) add `query GetFoo @catchByDefault(to: NULL) {}` on all operations/fragments (this is a no-op).
1. From this moment on, new queries written throw on errors by default.
1. Remove `query GetFoo @catchByDefault(to: NULL) {}` progressively.

## Migrate from `@nonnull`

If you were using `@nonnull` before, you can now use `@semanticNonNull`.

`@semanticNonNull`, coupled with `@catch` is more flexible and also more in line with other frameworks.

**For usages in executable documents**:
```graphql
# Replace
query GetFoo {
foo @nonnull
}

# With
query GetFoo {
foo @catch(to: THROW)
}
```

**For usages in schema documents**:
```graphql
# Replace
extend type Foo @nonnull(fields: "bar")

# With
extend type Foo @semanticNonNullField(name: "bar")
```

If your schema is configured with `@catchByDefault(to: NULL)`, you'll also need to update the usages in your executable documents:

```graphql
# Add `@catch(to: THROW)`
query GetFoo {
foo @catch(to: THROW)
}
```
4 changes: 2 additions & 2 deletions docs/source/advanced/plugin-recipes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ apollo {

## Combining multiple schema files

Apollo Kotlin supports a collection of client directives, including `@nonnull`, `@optional`, and `@typePolicy`. These
directives enable you to extend your server's base schema with client-specific types and fields.
Apollo Kotlin supports a collection of directives, such as `@semanticNonNull`, `@fieldPolicy`, `@typePolicy`. These
directives enable you to extend your server's base schema to work better with your client.

If you expand your schema in a separate file (usually named `extra.graphqls`), you can instruct Apollo Kotlin to construct its schema from a combination
of multiple files, like so:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
query MyQuery {
<caret>person {
identity {
firstName @nonnull
firstName @catch(to: THROW)
lastName
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
extend schema @link(
url: "https://specs.apollo.dev/nullability/v0.4",
import: ["@semanticNonNull", "@semanticNonNullField", "@catch", "CatchTo", "@catchByDefault"]
)
extend schema @catchByDefault(to: NULL)

type Query {
person: Person
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface Operation<D : Operation.Data> : Executable<D> {
/**
* The GraphQL operation String to be sent to the server. This might differ from the input `*.graphql` file with:
* - whitespaces removed
* - Apollo client directives like `@nonnull` removed
* - Apollo client directives like `@catch` removed
* - `typename` fields added for polymorphic/fragment cases
*/
fun document(): String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class AnonymousOperation(override val message: String, override val sourceLocati
class OtherValidationIssue(override val message: String, override val sourceLocation: SourceLocation?) : GraphQLValidationIssue

/**
* A deprecated field/enum is used
* A deprecated field/inputField/enumValue/directive is used
*/
class DeprecatedUsage(override val message: String, override val sourceLocation: SourceLocation?) : ApolloIssue

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ private class ForeignSchema(
/**
* Parses the schema extensions
*
* Example: extend schema @link(url: "https://specs.apollo.dev/kotlin_labs/v0.3", import: ["@nonnull"])
* Example: extend schema @link(url: "https://specs.apollo.dev/nullability/v0.4/", import: ["@catchByDefault", "CatchTo"])
*/
private fun List<GQLSchemaExtension>.getForeignSchemas(
issues: MutableList<Issue>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ internal fun ValidationScope.validateDirectives(
* Extra Apollo-specific validation for @nonnull
*/
internal fun ValidationScope.extraValidateNonNullDirective(directive: GQLDirective, directiveContext: GQLNode) {
issues.add(
DeprecatedUsage(message = "Using `@nonnull` is deprecated. Use `@semanticNonNull` and/or `@catch` instead. See https://go.apollo.dev/ak-nullability.", directive.sourceLocation)
)
if (directiveContext is GQLField && directive.arguments.isNotEmpty()) {
registerIssue(
message = "'${directive.name}' cannot have arguments when applied on a field",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,8 @@ directive @catch(to: CatchTo! = RESULT, levels: [Int!]! = [0]) on FIELD
""${'"'}
Indicates how clients should handle errors on a given position by default.
The semantics are the same as `@catch` but `@catchByDefault` only applies to positions that
can contain JSON `null`. Non-null positions are unchanged.
Compared to `@catch`, `@catchByDefault` does not have a `level` argument and applies to all
nullable positions.
When multiple values of `catchTo` are set for a given position:
* the `@catch` value is used if set.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion samples/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
If you're looking for a specific feature (APQs, Codegen options, `@nonnull`, ...) the [integration-tests](../tests) have a lot of very focused examples of how to use Apollo Kotlin.
If you're looking for a specific feature (APQs, Codegen options, `@catch`, ...) the [integration-tests](../tests) have a lot of very focused examples of how to use Apollo Kotlin.

For more general examples demonstrating how to build an App end to end, check:

* https://github.com/apollographql/apollo-kotlin-tutorial for an **Android App** example
* https://github.com/joreilly/MortyComposeKMM for a **Multiplatform App** example
* https://github.com/joreilly/Confetti for a **full fledged Android App** example

0 comments on commit 8e14023

Please sign in to comment.