@@ -676,6 +676,7 @@ type Arguments {
676
676
intArgField (intArg : Int ): Int
677
677
nonNullBooleanArgField (nonNullBooleanArg : Boolean ! ): Boolean !
678
678
booleanListArgField (booleanListArg : [Boolean ]! ): [Boolean ]
679
+ optionalNonNullBooleanArgField (optionalBooleanArg : Boolean ! = false ): Boolean !
679
680
}
680
681
681
682
extend type Query {
@@ -710,25 +711,25 @@ and invalid.
710
711
* {arguments} must be the set containing only {argument}.
711
712
712
713
713
- #### Required Non-Null Arguments
714
+ #### Required Arguments
714
715
715
716
* For each Field or Directive in the document.
716
717
* Let {arguments} be the arguments provided by the Field or Directive.
717
718
* Let {argumentDefinitions} be the set of argument definitions of that Field or Directive.
718
- * For each {definition} in {argumentDefinitions}:
719
- * Let {type} be the expected type of {definition}.
720
- * If {type} is Non-Null:
721
- * Let {argumentName} be the name of {definition}.
719
+ * For each {argumentDefinition} in {argumentDefinitions}:
720
+ * Let {type} be the expected type of {argumentDefinition}.
721
+ * Let {defaultValue} be the default value of {argumentDefinition}.
722
+ * If {type} is Non-Null and {defaultValue} does not exist:
723
+ * Let {argumentName} be the name of {argumentDefinition}.
722
724
* Let {argument} be the argument in {arguments} named {argumentName}
723
725
* {argument} must exist.
724
726
* Let {value} be the value of {argument}.
725
727
* {value} must not be the {null} literal.
726
728
727
729
** Explanatory Text**
728
730
729
- Arguments can be required. If the argument type is non-null the argument is
730
- required and furthermore the explicit value {null} may not be provided.
731
- Otherwise, the argument is optional.
731
+ Arguments can be required. An argument is required if the argument type is
732
+ non-null and does not have a default value. Otherwise, the argument is optional.
732
733
733
734
For example the following are valid:
734
735
@@ -752,19 +753,20 @@ fragment goodBooleanArgDefault on Arguments {
752
753
}
753
754
```
754
755
755
- but this is not valid on a non-null argument.
756
+ but this is not valid on a required argument.
756
757
757
758
``` graphql counter-example
758
759
fragment missingRequiredArg on Arguments {
759
760
nonNullBooleanArgField
760
761
}
761
762
```
762
763
763
- Providing the explicit value {null} is also not valid.
764
+ Providing the explicit value {null} is also not valid since required arguments
765
+ always have a non-null type.
764
766
765
767
``` graphql counter-example
766
768
fragment missingRequiredArg on Arguments {
767
- notNullBooleanArgField (nonNullBooleanArg : null )
769
+ nonNullBooleanArgField (nonNullBooleanArg : null )
768
770
}
769
771
```
770
772
@@ -1358,6 +1360,31 @@ For example the following query will not pass validation.
1358
1360
```
1359
1361
1360
1362
1363
+ ### Input Object Required Fields
1364
+
1365
+ ** Formal Specification**
1366
+
1367
+ * For each Input Object in the document.
1368
+ * Let {fields} be the fields provided by that Input Object.
1369
+ * Let {fieldDefinitions} be the set of input field definitions of that Input Object.
1370
+ * For each {fieldDefinition} in {fieldDefinitions}:
1371
+ * Let {type} be the expected type of {fieldDefinition}.
1372
+ * Let {defaultValue} be the default value of {fieldDefinition}.
1373
+ * If {type} is Non-Null and {defaultValue} does not exist:
1374
+ * Let {fieldName} be the name of {fieldDefinition}.
1375
+ * Let {field} be the input field in {fields} named {fieldName}
1376
+ * {field} must exist.
1377
+ * Let {value} be the value of {field}.
1378
+ * {value} must not be the {null} literal.
1379
+
1380
+ ** Explanatory Text**
1381
+
1382
+ Input object fields may be required. Much like a field may have required
1383
+ arguments, an input object may have required fields. An input field is required
1384
+ if it has a non-null type and does not have a default value. Otherwise, the
1385
+ input object field is optional.
1386
+
1387
+
1361
1388
## Directives
1362
1389
1363
1390
@@ -1494,44 +1521,6 @@ fragment HouseTrainedFragment {
1494
1521
```
1495
1522
1496
1523
1497
- ### Variable Default Value Is Allowed
1498
-
1499
- ** Formal Specification**
1500
-
1501
- * For every Variable Definition {variableDefinition} in a document
1502
- * Let {variableType} be the type of {variableDefinition}
1503
- * Let {defaultValue} be the default value of {variableDefinition}
1504
- * If {variableType} is Non-null:
1505
- * {defaultValue} must be undefined.
1506
-
1507
- ** Explanatory Text**
1508
-
1509
- Variables defined by operations are allowed to define default values
1510
- if the type of that variable is not non-null.
1511
-
1512
- For example the following query will pass validation.
1513
-
1514
- ``` graphql example
1515
- query houseTrainedQuery ($atOtherHomes : Boolean = true ) {
1516
- dog {
1517
- isHousetrained (atOtherHomes : $atOtherHomes )
1518
- }
1519
- }
1520
- ```
1521
-
1522
- However if the variable is defined as non-null, default values
1523
- are unreachable. Therefore queries such as the following fail
1524
- validation
1525
-
1526
- ``` graphql counter-example
1527
- query houseTrainedQuery ($atOtherHomes : Boolean ! = true ) {
1528
- dog {
1529
- isHousetrained (atOtherHomes : $atOtherHomes )
1530
- }
1531
- }
1532
- ```
1533
-
1534
-
1535
1524
### Variables Are Input Types
1536
1525
1537
1526
** Formal Specification**
@@ -1833,20 +1822,45 @@ an extraneous variable.
1833
1822
1834
1823
** Formal Specification**
1835
1824
1836
- * For each {operation} in {document}
1837
- * Let {variableUsages} be all usages transitively included in the {operation}
1838
- * For each {variableUsage} in {variableUsages}
1839
- * Let {variableType} be the type of variable definition in the {operation}
1840
- * Let {argumentType} be the type of the argument the variable is passed to.
1841
- * Let {hasDefault} be true if the variable definition defines a default.
1842
- * AreTypesCompatible({argumentType}, {variableType}, {hasDefault}) must be true
1843
-
1844
- * AreTypesCompatible({argumentType}, {variableType}, {hasDefault}):
1845
- * If {hasDefault} is true, treat the {variableType} as non-null.
1846
- * If inner type of {argumentType} and {variableType} are different, return false
1847
- * If {argumentType} and {variableType} have different list dimensions, return false
1848
- * If any list level of {variableType} is not non-null, and the corresponding level
1849
- in {argument} is non-null, the types are not compatible.
1825
+ * For each {operation} in {document}:
1826
+ * Let {variableUsages} be all usages transitively included in the {operation}.
1827
+ * For each {variableUsage} in {variableUsages}:
1828
+ * Let {variableName} be the name of {variableUsage}.
1829
+ * Let {variableDefinition} be the {VariableDefinition} named {variableName}
1830
+ defined within {operation}.
1831
+ * {IsVariableUsageAllowed(variableDefinition, variableUsage)} must be {true}.
1832
+
1833
+ IsVariableUsageAllowed(variableDefinition, variableUsage):
1834
+ * Let {variableType} be the expected type of {variableDefinition}.
1835
+ * Let {locationType} be the expected type of the {Argument}, {ObjectField},
1836
+ or {ListValue} entry where {variableUsage} is located.
1837
+ * If {locationType} is a non-null type AND {variableType} is NOT a non-null type:
1838
+ * Let {hasNonNullVariableDefaultValue} be {true} if a default value exists
1839
+ for {variableDefinition} and is not the value {null}.
1840
+ * Let {hasLocationDefaultValue} be {true} if a default value exists for
1841
+ the {Argument} or {ObjectField} where {variableUsage} is located.
1842
+ * If {hasNonNullVariableDefaultValue} is NOT {true} AND
1843
+ {hasLocationDefaultValue} is NOT {true}, return {false}.
1844
+ * Let {nullableLocationType} be the unwrapped nullable type of {locationType}.
1845
+ * Return {AreTypesCompatible(variableType, nullableLocationType)}.
1846
+ * Return {AreTypesCompatible(variableType, locationType)}.
1847
+
1848
+ AreTypesCompatible(variableType, locationType):
1849
+ * If {locationType} is a non-null type:
1850
+ * If {variableType} is NOT a non-null type, return {false}.
1851
+ * Let {nullableLocationType} be the unwrapped nullable type of {locationType}.
1852
+ * Let {nullableVariableType} be the unwrapped nullable type of {variableType}.
1853
+ * Return {AreTypesCompatible(nullableVariableType, nullableLocationType)}.
1854
+ * Otherwise, if {variableType} is a non-null type:
1855
+ * Let {nullableVariableType} be the nullable type of {variableType}.
1856
+ * Return {AreTypesCompatible(nullableVariableType, locationType)}.
1857
+ * Otherwise, if {locationType} is a list type:
1858
+ * If {variableType} is NOT a list type, return {false}.
1859
+ * Let {itemLocationType} be the unwrapped item type of {locationType}.
1860
+ * Let {itemVariableType} be the unwrapped item type of {variableType}.
1861
+ * Return {AreTypesCompatible(itemVariableType, itemLocationType)}.
1862
+ * Otherwise, if {variableType} is a list type, return {false}.
1863
+ * Return {true} if {variableType} and {locationType} are identical, otherwise {false}.
1850
1864
1851
1865
** Explanatory Text**
1852
1866
@@ -1890,17 +1904,6 @@ query booleanArgQuery($booleanArg: Boolean) {
1890
1904
}
1891
1905
```
1892
1906
1893
- A notable exception is when default arguments are provided. They are, in effect,
1894
- treated as non-nulls.
1895
-
1896
- ``` graphql example
1897
- query booleanArgQueryWithDefault ($booleanArg : Boolean = true ) {
1898
- arguments {
1899
- nonNullBooleanArgField (nonNullBooleanArg : $booleanArg )
1900
- }
1901
- }
1902
- ```
1903
-
1904
1907
For list types, the same rules around nullability apply to both outer types
1905
1908
and inner types. A nullable list cannot be passed to a non-null list, and a list
1906
1909
of nullable values cannot be passed to a list of non-null values.
@@ -1925,5 +1928,36 @@ query listToNonNullList($booleanList: [Boolean]) {
1925
1928
```
1926
1929
1927
1930
This would fail validation because a ` [T] ` cannot be passed to a ` [T]! ` .
1928
-
1929
1931
Similarly a ` [T] ` cannot be passed to a ` [T!] ` .
1932
+
1933
+ ** Allowing optional variables when default values exist**
1934
+
1935
+ A notable exception to typical variable type compatibility is allowing a
1936
+ variable definition with a nullable type to be provided to a non-null location
1937
+ as long as either that variable or that location provides a default value.
1938
+
1939
+ ``` graphql example
1940
+ query booleanArgQueryWithDefault ($booleanArg : Boolean ) {
1941
+ arguments {
1942
+ optionalNonNullBooleanArgField (optionalBooleanArg : $booleanArg )
1943
+ }
1944
+ }
1945
+ ```
1946
+
1947
+ In the example above, an optional variable is allowed to be used in an non-null argument which provides a default value.
1948
+
1949
+ ``` graphql example
1950
+ query booleanArgQueryWithDefault ($booleanArg : Boolean = true ) {
1951
+ arguments {
1952
+ nonNullBooleanArgField (nonNullBooleanArg : $booleanArg )
1953
+ }
1954
+ }
1955
+ ```
1956
+
1957
+ In the example above, a variable provides a default value and can be used in a
1958
+ non-null argument. This behavior is explicitly supported for compatibility with
1959
+ earlier editions of this specification. GraphQL authoring tools may wish to
1960
+ report this is a warning with the suggestion to replace ` Boolean ` with ` Boolean! ` .
1961
+
1962
+ Note: The value {null} could still be provided to a such a variable at runtime.
1963
+ A non-null argument must produce a field error if provided a {null} value.
0 commit comments