Skip to content

@semanticNonNullField does not force non-nullable Kotlin type for nullable schema fields #6789

@yt8492

Description

@yt8492

Version

5.0.0-alpha.2

Summary

I am migrating from the deprecated @nonnull directive to the new nullability spec directives in Apollo Kotlin v5, as described in the official documentation: Migrate from @nonnull.

The issue is that when applying @semanticNonNullField to a field that is explicitly nullable in the GraphQL schema, the generated Kotlin property remains nullable, which is not the expected behavior for a directive designed to override semantic nullability.

This is my example repository. You can reproduce this problem.
https://github.com/yt8492/ApolloPlayground

Steps to reproduce the behavior

  1. Define the GraphQL Schema:
schema {
    query: Query
}

type Query {
    foo: Foo!
}

type Foo {
    id: ID!
    bar: Bar # Nullable in the schema
}

type Bar {
    id: ID!
}
  1. Define extra.graphqls to enforce non-nullability for Foo.bar:
extend schema @link(
    url: "[https://specs.apollo.dev/nullability/v0.4](https://specs.apollo.dev/nullability/v0.4)",
    import: ["@semanticNonNull", "@semanticNonNullField", "@catch", "CatchTo", "@catchByDefault"]
)
# Applying a default catch strategy for completeness, though not strictly required for this specific issue.
extend schema @catchByDefault(to: NULL)

# Attempt to make the schema-nullable field 'bar' semantically non-null
extend type Foo @semanticNonNullField(name: "bar")
  1. Define a sample Query:
query ExampleQuery {
    foo {
        id
        bar {
            id
        }
    }
}
  1. Observe the Generated Kotlin Code:

In the generated Kotlin data class for the query, the bar property is of type Bar?, despite the @semanticNonNullField directive.

public data class Foo(
  public val id: String,
  public val bar: Bar?,
)
  1. Usage demonstrating the issue:

The code still requires a safe call (?.) on bar, confirming it is nullable:

fun main(): Unit = runBlocking {
  val apollo = ApolloClient.Builder().build()
  apollo.query(ExampleQuery())
    .execute()
    .dataOrThrow()
    .foo
    .bar
    ?.id // The 'bar' property is still nullable, requiring the safe call.
}

Logs

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions