graphql / graphql/graphql-spec

Optional v. Nullable input redux

Open
#872 4 comments 8 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
14.6k
Forks
1.2k
PR merge metrics
No merged PRs in 30d

Description

An alternative proposal for the often requested (#476, #542) ability to distinguish optional inputs from nullable inputs. It doesn't propose any change to core GraphQL, just conventions and directives.

It can be summarized as:
* Encourage using default values wherever possible, even a default of `null`.
* Use standard directives as documentation. Extensions are free to implement validation based on the directives, but that's not part of the proposal.

## Directives
```graphql
"""
This input is optional, not nullable.
If the client insists on sending an explicit null value, the behavior is undefined.
"""
directive @optional on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION

"""
This input is nullable, not optional.
If the client insists on omitting the input value, the behavior is undefined.
"""
directive @required on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
```

## Usage
Nullability | Optionality | Defaults | Definition
----------- | ----------- | --------------- | ----------
Non-Null | Required | | `Type!`
Non-Null | Optional | Has Default | `Type! = value`
Non-Null | Optional | No Default | `Type @optional`
Nullable | Required | | `Type @required`
Nullable | Optional | Omitted == null | `Type = null`
Nullable | Optional | Omitted != null | `Type`

## Descriptions
### `Type!`
Works as always.

### `Type! = value`
Already supported, just needs more documentation and encouragement. It may come as a surprise in this forum, but many developers don't know that an input can have a default, or that a default alone makes it optional.
* The [introductory example](https://graphql.org/learn/schema/#arguments) uses a nullable: `length(unit: LengthUnit = METER): Float`. Using `LengthUnit!` would make the example clearer.
* The [spec contains conflicting statements](http://spec.graphql.org/June2018/#sec-Type-System.Non-Null) which have become conventional wisdom:
> For the sake of simplicity nullable types are always optional and non‐null types are always required.

### `Type @optional`
The client knows that the service doesn't want an explicit `null`.

### `Type @required`
The client knows that the service doesn't want an omitted input. Arguably this use case doesn't exist organically; it's for those who want to return an error on principle.

### `Type = null`
Already supported; presumably it's not common because it appears pointless. But it has an important point in this context: guaranteeing to the client that omission and explicit null behave identically.

### `Type`
Works as always, but with a different implication. Clients can infer that omission and explicit nulls have [different semantics](http://spec.graphql.org/June2018/#sec-Input-Objects), otherwise one of the other options should have been chosen. A partial update mutation is the typical example, but this is common in queries as well. Consider filter predicates like `(equal: String, contains: String, ...)`. `null` is likely a valid input to `equal`, and omission indicates to not filter. Whereas `contains` is likely being forced to be nullable, and could be annotated with `@optional` instead.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.