Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: (graphcache) - Nullability Operators #2018

Closed
wants to merge 6 commits into from
Closed

Conversation

kitten
Copy link
Member

@kitten kitten commented Oct 8, 2021

A preview of this change has been published under the spec-nullability tag.

Context

The "Nullability RFC" for GraphQL allows fields to individually be marked as optional or required in a query by the client-side. (See Strawman Proposal)

If a field is marked as optional then it's allowed to be missing and null, which
can control where missing values cascade to:

query {
  me {
    name?
  }
}

If a field is marked as required it may never be allowed to become null and must
cascade if it otherwise would have been set to null:

query {
  me {
    name!
  }
}

Summary

This is extremely interesting for us in Graphcache. Currently, "schema awareness" is very tangential to this idea. When schema information is available in Graphcache, we're able to read a field and react to a cache miss accordingly. We can independently cascade across non-nullable fields upwards and set the result to null partially.

However, this feature is dependent entirely on the user's schema, and furthermore, is not accessible to anyone who isn't using schema awareness.

When a field is marked as nullable and schema awareness is enabled, then Graphcache will automatically deliver partial results, without the UI being able to indicate beforehand if that's desired. Now, a field may be set to "required" (i.e. { field! }), which means that this can be prevented.

Similarly, even without schema awareness entire fields may be marked as optional (i.e. { field? }), which enables Graphcache to act as if the schema described this field as nullable, which allows us to actively craft a partial result, even if schema awareness isn't enabled, since we know that this field may in fact be null.

In other words, the nullability RFC guarantees a "forced outcome" in both cases, without having to
look up whether a field is nullable in the schema.
In the future, we may even derive the RequiredStatus of a FieldNode in an
external place and never call isFieldNullable with a schema in the query
traversal.

Set of changes

  • Add temporary ExtendedFieldNode type in iterator
  • Add additional check for field.required in readSelection

An implementation for graphql-js exists, but I've created a separate PR against the graphql-web-lite overlay package, which is published and can be used to test this change, as long as an API supports this. This has been published to npm under the spec-nullability tag.

Note: This PR currently strips out the nullability operators before forwarding the query. This is temporary for testing. This isn't what we'd ship, since we assume that we can trust the result to correspond to the operation document.

Further Considerations

  • This may be interesting for useFragment and fragment masking, See RFC: Fragment Suspense boundaries in React bindings #1408
  • This raises a case of what happens when a field marked as nullable is written to the cache. We may have dissonance here when a field is marked as nullable but is required in the schema; if the same field is then unmarked, we run the risk of setting a required field to null. Maybe we have to skip caching it then, if we don't have schema awareness turned on. (Solved by erasing field instead)

The ["Nullability RFC" for GraphQL](graphql/graphql-wg#694)
allows fields to individually be marked as optional or required in a query by the
client-side. ([See Strawman Proposal](graphql/graphql-spec#867))

If a field is marked as optional then it's allowed to be missing and `null`, which
can control where missing values cascade to:

```graphql
query {
  me {
    name?
  }
}
```

If a field is marked as required it may never be allowed to become `null` and must
cascade if it otherwise would have been set to `null`:

```graphql
query {
  me {
    name!
  }
}
```

In Graphcache, we imagine that the nullable field — which would be marked with
`required: 'optional'` — can allow Graphcache to make more data nullable and
hence partial, which enhances schema awareness, even if it's not actively used.

The required fields — which would be marked with `required: 'required'` — would
force Graphcache to include this data, regardless of what schema awareness may
say, which also enhances partial data in the presence of schema awareness, since
it increases what the cache may deliver.

In other words, it guarantees a "forced outcome" in both cases, without having to
look up whether a field is nullable in the schema.
In the future, we may even derive the `RequiredStatus` of a `FieldNode` in an
external place and never call `isFieldNullable` with a schema in the query
traversal.
@changeset-bot
Copy link

changeset-bot bot commented Oct 8, 2021

⚠️ No Changeset found

Latest commit: 2e1af29

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@frederikhors
Copy link
Contributor

I love you guys. 😍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants