@@ -676,6 +676,7 @@ type Arguments {
676676 intArgField (intArg : Int ): Int
677677 nonNullBooleanArgField (nonNullBooleanArg : Boolean ! ): Boolean !
678678 booleanListArgField (booleanListArg : [Boolean ]! ): [Boolean ]
679+ optionalNonNullBooleanArgField (optionalBooleanArg : Boolean ! = false ): Boolean !
679680}
680681
681682extend type Query {
@@ -710,25 +711,25 @@ and invalid.
710711 * {arguments} must be the set containing only {argument}.
711712
712713
713- #### Required Non-Null Arguments
714+ #### Required Arguments
714715
715716 * For each Field or Directive in the document.
716717 * Let {arguments} be the arguments provided by the Field or Directive.
717718 * 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}.
722724 * Let {argument} be the argument in {arguments} named {argumentName}
723725 * {argument} must exist.
724726 * Let {value} be the value of {argument}.
725727 * {value} must not be the {null} literal.
726728
727729** Explanatory Text**
728730
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.
732733
733734For example the following are valid:
734735
@@ -752,19 +753,20 @@ fragment goodBooleanArgDefault on Arguments {
752753}
753754```
754755
755- but this is not valid on a non-null argument.
756+ but this is not valid on a required argument.
756757
757758``` graphql counter-example
758759fragment missingRequiredArg on Arguments {
759760 nonNullBooleanArgField
760761}
761762```
762763
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.
764766
765767``` graphql counter-example
766768fragment missingRequiredArg on Arguments {
767- notNullBooleanArgField (nonNullBooleanArg : null )
769+ nonNullBooleanArgField (nonNullBooleanArg : null )
768770}
769771```
770772
@@ -1358,6 +1360,31 @@ For example the following query will not pass validation.
13581360```
13591361
13601362
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+
13611388## Directives
13621389
13631390
@@ -1494,44 +1521,6 @@ fragment HouseTrainedFragment {
14941521```
14951522
14961523
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-
15351524### Variables Are Input Types
15361525
15371526** Formal Specification**
@@ -1833,20 +1822,45 @@ an extraneous variable.
18331822
18341823** Formal Specification**
18351824
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}.
18501864
18511865** Explanatory Text**
18521866
@@ -1890,17 +1904,6 @@ query booleanArgQuery($booleanArg: Boolean) {
18901904}
18911905```
18921906
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-
19041907For list types, the same rules around nullability apply to both outer types
19051908and inner types. A nullable list cannot be passed to a non-null list, and a list
19061909of nullable values cannot be passed to a list of non-null values.
@@ -1925,5 +1928,36 @@ query listToNonNullList($booleanList: [Boolean]) {
19251928```
19261929
19271930This would fail validation because a ` [T] ` cannot be passed to a ` [T]! ` .
1928-
19291931Similarly 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