Skip to content

Commit 4f40177

Browse files
committed
CoerceInputValue()
1 parent bc4ddea commit 4f40177

File tree

3 files changed

+283
-111
lines changed

3 files changed

+283
-111
lines changed

spec/Section 3 -- Type System.md

Lines changed: 177 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,46 @@ IsOutputType(type):
383383
- Return {true}.
384384
- Return {false}.
385385

386+
### Input Coercion
387+
388+
CoerceInputValue(type, value, variableValues):
389+
390+
- Assert: {IsInputType(type)}.
391+
- If {type} is a Non-Null type:
392+
- If {value} is {null}, raise a _coercion failure_.
393+
- Let {innerType} be the _inner type_ of {type}.
394+
- Return the result of calling {CoerceInputValue(innerType, value,
395+
variableValues)}.
396+
- If {value} is {null}, return {null}.
397+
- If {type} is a List type, return the result of {CoerceInputListValue(type,
398+
value, variableValues)}.
399+
- If {type} is an Input Object type, return the result of
400+
{CoerceInputObjectValue(type, value, variableValues)}.
401+
- If {type} is an Enum type, return the result of {CoerceInputEnumValue(type,
402+
value)}.
403+
- Otherwise, return the result of {CoerceScalarValue(type, value)}.
404+
405+
Input coercion defines the requirements for how an value is transformed into a
406+
canonical form expected by the internal GraphQL service, including the
407+
resolution of any variables (see {ResolveVariable()}). This allows GraphQL to
408+
provide consistent guarantees about inputs to field resolution atop any
409+
service's internal runtime or network serialization.
410+
411+
:: Failure to meet these requirements results in _coercion failure_, which may
412+
occur during different phases of a GraphQL service, each of which results in a
413+
different type of error. As a result, each phase specifically describes how to
414+
handle a coercion failure:
415+
416+
- During schema construction (i.e. a default value for an argument definition),
417+
failure results in an invalid schema.
418+
- During document validation (i.e. a value literal directly within an
419+
operation), failure results in document invalidation, which raises a _request
420+
error_.
421+
- During coercion of values provided for variables as part of a request, failure
422+
results in a _request error_.
423+
- During coercion of field arguments, failure results in an _execution error_,
424+
however validation and variable value coercion should make this uncommon.
425+
386426
### Type Extensions
387427

388428
TypeExtension :
@@ -502,10 +542,17 @@ information on the serialization of scalars in common JSON and other formats.
502542

503543
**Input Coercion**
504544

545+
CoerceScalarValue(scalarType, value):
546+
547+
- Assert: value is not {null}, which is already handled in {CoerceInputValue()}.
548+
- Return the result of calling the internal method provided by the type system
549+
for determining theinput coercionof {scalarType} given the value {value}.
550+
This internal method must return a valid value for the type and not {null}.
551+
Otherwise raise a _coercion failure_.
552+
505553
If a GraphQL service expects a scalar type as input to an argument, coercion is
506554
observable and the rules must be well defined. If an input value does not match
507-
a coercion rule, a _request error_ must be raised (input values are validated
508-
before execution begins).
555+
a coercion rule, it results in _coercion failure_.
509556

510557
GraphQL has different constant literals to represent integer and floating-point
511558
input values, and coercion rules may apply differently depending on which type
@@ -516,8 +563,9 @@ floating-point values, they are interpreted as an integer input value if they
516563
have an empty fractional part (ex. `1.0`) and otherwise as floating-point input
517564
value.
518565

519-
For all types below, with the exception of Non-Null, if the explicit value
520-
{null} is provided, then the result of input coercion is {null}.
566+
Note: {null} is a valid input value for all scalar types except those wrapped by
567+
a _Non-Null type_, however {null} value coercion is handled in
568+
{CoerceInputValue()} before {CoerceScalarValue()} is called.
521569

522570
### Int
523571

@@ -544,10 +592,9 @@ greater than or equal to 2<sup>31</sup>, an _execution error_ should be raised.
544592
**Input Coercion**
545593

546594
When expected as an input type, only integer input values are accepted. All
547-
other input values, including strings with numeric content, must raise a request
548-
error indicating an incorrect type. If the integer input value represents a
549-
value less than -2<sup>31</sup> or greater than or equal to 2<sup>31</sup>, a
550-
_request error_ should be raised.
595+
other input values, including strings with numeric content result in _coercion
596+
failure_ indicating an incorrect type. Input values less than -2<sup>31</sup> or
597+
greater than or equal to 2<sup>31</sup> result in _coercion failure_.
551598

552599
Note: Numeric integer values larger than 32-bit should either use String or a
553600
custom-defined Scalar type, as not all platforms and transports support encoding
@@ -578,10 +625,10 @@ coerced to {Float} and must raise an _execution error_.
578625
When expected as an input type, both integer and float input values are
579626
accepted. Integer input values are coerced to Float by adding an empty
580627
fractional part, for example `1.0` for the integer input value `1`. All other
581-
input values, including strings with numeric content, must raise a _request
582-
error_ indicating an incorrect type. If the input value otherwise represents a
583-
value not representable by finite IEEE 754 (e.g. {NaN}, {Infinity}, or a value
584-
outside the available precision), a _request error_ must be raised.
628+
input values, including strings with numeric content, result in _coercion
629+
failure_ indicating an incorrect type. Input values not representable by finite
630+
IEEE 754 (e.g. {NaN}, {Infinity}, or a value outside the available precision)
631+
result in _coercion failure_.
585632

586633
### String
587634

@@ -604,8 +651,7 @@ value, or the string `"1"` for the integer `1`.
604651
**Input Coercion**
605652

606653
When expected as an input type, only valid Unicode string input values are
607-
accepted. All other input values must raise a _request error_ indicating an
608-
incorrect type.
654+
accepted. All other input values result in _coercion failure_.
609655

610656
### Boolean
611657

@@ -624,7 +670,7 @@ Examples of this may include returning `true` for non-zero numbers.
624670
**Input Coercion**
625671

626672
When expected as an input type, only boolean input values are accepted. All
627-
other input values must raise a _request error_ indicating an incorrect type.
673+
other input values result in _coercion failure_.
628674

629675
### ID
630676

@@ -647,9 +693,8 @@ When coercion is not possible they must raise an _execution error_.
647693

648694
When expected as an input type, any string (such as `"4"`) or integer (such as
649695
`4` or `-4`) input value should be coerced to ID as appropriate for the ID
650-
formats a given GraphQL service expects. Any other input value, including float
651-
input values (such as `4.0`), must raise a _request error_ indicating an
652-
incorrect type.
696+
formats a given GraphQL service expects. All other input values, including float
697+
input values (such as `4.0`), result in _coercion failure_.
653698

654699
### Scalar Extensions
655700

@@ -914,7 +959,7 @@ executor, see [Value Completion](#sec-Value-Completion).
914959

915960
**Input Coercion**
916961

917-
Objects are never valid inputs.
962+
Object types are never valid inputs. See [Input Objects](#sec-Input-Objects).
918963

919964
**Type Validation**
920965

@@ -938,8 +983,8 @@ of rules must be adhered to by every Object type in a GraphQL schema.
938983
returns {true}.
939984
4. If argument type is Non-Null and a default value is not defined:
940985
1. The `@deprecated` directive must not be applied to this argument.
941-
5. If the argument has a default value it must be compatible with
942-
{argumentType} as per the coercion rules for that type.
986+
5. If the argument has a default value, {CoerceInputValue(argumentType,
987+
defaultValue)} must not result in _coercion failure_.
943988
3. An object type may declare that it implements one or more unique interfaces.
944989
4. An object type must be a super-set of all interfaces it implements:
945990
1. Let this object type be {objectType}.
@@ -1044,6 +1089,26 @@ May return the result:
10441089
The type of an object field argument must be an input type (any type except an
10451090
Object, Interface, or Union type).
10461091

1092+
**Default Values**
1093+
1094+
GetDefaultValue(inputValueDefinition):
1095+
1096+
- Assert: {inputValueDefinition} has a {DefaultValue}, as this is only called
1097+
when true.
1098+
- Let {inputType} be the type of {inputValueDefinition}.
1099+
- Let {defaultValue} be the default value of {inputValueDefinition}
1100+
- Return the result of {CoerceInputValue(inputType, defaultValue, null)}. (Note:
1101+
default values must not contain variable references)
1102+
1103+
A default value may be provided for a field argument, input object field, or
1104+
variable definitions. If at runtime a value is not provided, the coerced default
1105+
value is used instead.
1106+
1107+
Note: Implementations are encouraged to optimize the coercion of a default value
1108+
by doing so only once and caching the resulting coerced value. This should not
1109+
result in request execution _coercion failure_ since all default values should
1110+
be validated before a request.
1111+
10471112
### Field Deprecation
10481113

10491114
Fields in an object may be marked as deprecated as deemed necessary by the
@@ -1291,6 +1356,8 @@ Interface types have the potential to be invalid if incorrectly defined.
12911356
arguments may share the same name.
12921357
3. The argument must accept a type where {IsInputType(argumentType)}
12931358
returns {true}.
1359+
4. If a argument has a default value, {CoerceInputValue(argumentType,
1360+
defaultValue)} must not result in _coercion failure_.
12941361
3. An interface type may declare that it implements one or more unique
12951362
interfaces, but may not implement itself.
12961363
4. An interface type must be a super-set of all interfaces it implements:
@@ -1517,15 +1584,24 @@ reasonable coercion is not possible they must raise an _execution error_.
15171584

15181585
**Input Coercion**
15191586

1520-
GraphQL has a constant literal to represent enum input values. GraphQL string
1521-
literals must not be accepted as an enum input and instead raise a request
1522-
error.
1587+
CoerceInputEnumValue(type, value):
1588+
1589+
- Assert: value is not {null}, which is already handled in {CoerceInputValue()}.
1590+
- If {value} represents a name (such as {EnumValue}), let {name} be the name of
1591+
{value}:
1592+
- If Enum {type} has a member named {name}, let it be {member}:
1593+
- Return the internal value representing {member}.
1594+
- Otherwise raise a _coercion failure_.
1595+
1596+
GraphQL has a constant literal, {EnumValue}, used to represent enum input
1597+
values. GraphQL {StringValue} literals must not be accepted as an enum input and
1598+
instead result in a _coercion failure_.
15231599

15241600
Variable transport serializations which have a different representation for
15251601
non-string symbolic values (for example,
15261602
[EDN](https://github.com/edn-format/edn)) should only allow such values as enum
15271603
input values. Otherwise, for most transport serializations that do not, strings
1528-
may be interpreted as the enum input value with the same name.
1604+
may be interpreted as the enum member of the same name.
15291605

15301606
**Type Validation**
15311607

@@ -1649,11 +1725,47 @@ type of an Object or Interface field.
16491725

16501726
**Input Coercion**
16511727

1728+
CoerceInputObjectValue(type, value, variableValues):
1729+
1730+
- If {value} is not an {ObjectValue} or map of values, raise a _coercion
1731+
failure_.
1732+
- Let {coercedValues} be an empty map.
1733+
- Let {inputFieldDefinitions} be the input fields defined by {type}:
1734+
- For each {inputFieldDefinition} in {inputFieldDefinitions}:
1735+
- Let {inputFieldName} be the name of {inputFieldDefinition}.
1736+
- Let {inputFieldType} be the expected type of {inputFieldDefinition}.
1737+
- Assert: {IsInputType(inputFieldType)}, because of
1738+
[type validation](#sec-Input-Objects.Type-Validation).
1739+
- If {value} has an entry with name {inputFieldName}, let {inputFieldValue} be
1740+
its value:
1741+
- If {inputFieldValue} is a {Variable}, let {variableName} be its name:
1742+
- Let {isProvided}, {variableValue} be the result of
1743+
{ResolveVariable(type, variableName, variableValues)}.
1744+
- If {isProvided} is {true}, add an entry to {coercedValues} named
1745+
{inputFieldName} with the value {variableValue}.
1746+
- Otherwise if {inputFieldDefinition} has a default value, add an entry to
1747+
{coercedValues} named {inputFieldName} with the value
1748+
{GetDefaultValue(inputFieldDefinition)}.
1749+
- Otherwise:
1750+
- Let {coercedValue} be the result of {CoerceInputValue(inputFieldType,
1751+
inputFieldValue, variableValues)}.
1752+
- Add an entry to {coercedValues} named {inputFieldName} with the value
1753+
{coercedValue}.
1754+
- Otherwise if {inputFieldDefinition} has a default value, add an entry to
1755+
{coercedValues} named {inputFieldName} with the value
1756+
{GetDefaultValue(inputFieldDefinition)}.
1757+
- Otherwise if {inputFieldType} is a Non-Null type, raise an _coercion
1758+
failure_.
1759+
- Return {coercedValues}.
1760+
1761+
Note: This algorithm is very similar to {CoerceArgumentValues()}, as both are
1762+
defined with {InputValueDefinition}.
1763+
16521764
The value for an input object should be an input object literal or an unordered
1653-
map supplied by a variable, otherwise a _request error_ must be raised. In
1765+
map supplied by a variable, otherwise it results in _coercion failure_. In
16541766
either case, the input object literal or unordered map must not contain any
1655-
entries with names not defined by a field of this input object type, otherwise a
1656-
request error must be raised.
1767+
entries with names not defined by a field of this input object type, otherwise
1768+
it results in _coercion failure_.
16571769

16581770
The result of coercion is an unordered map with an entry for each field both
16591771
defined by the input object type and for which a value exists. The resulting map
@@ -1723,6 +1835,9 @@ input ExampleInputObject {
17231835
returns {true}.
17241836
4. If input field type is Non-Null and a default value is not defined:
17251837
1. The `@deprecated` directive must not be applied to this input field.
1838+
5. If the input object field has a default value,
1839+
{CoerceInputValue(inputObjectType, defaultValue)} must not result in
1840+
_coercion failure_.
17261841
3. If an Input Object references itself either directly or through referenced
17271842
Input Objects, at least one of the fields in the chain of references must be
17281843
either a nullable or a List type.
@@ -1819,19 +1934,44 @@ about this behavior.
18191934

18201935
**Input Coercion**
18211936

1937+
CoerceInputListValue(type, value, variableValues):
1938+
1939+
- Assert: value is not {null}, which is already handled in {CoerceInputValue()}.
1940+
- Let {coercedValues} be an empty list.
1941+
- Let {itemType} be the _inner type_ of {type}.
1942+
- If {value} is a list:
1943+
- For each {itemValue} in {value}:
1944+
- If {itemValue} is a {Variable}, let {variableName} be its name:
1945+
- Let {isProvided}, {variableValue} be the result of
1946+
{ResolveVariable(type, variable, variableValues)}.
1947+
- Append {variableValue} to {coercedValues}. (Note: Variables without
1948+
provided values are replaced with {null})
1949+
- Otherwise:
1950+
- Let {coercedValue} be the result of {CoerceInputValue(itemType,
1951+
itemValue, variableValues)}.
1952+
- Append {coercedValue} to {coercedValues}.
1953+
- Otherwise:
1954+
- Let {coercedValue} be the result of {CoerceInputValue(itemType, value,
1955+
variableValues)}.
1956+
- Append {coercedValue} to {coercedValues}.
1957+
- Return {coercedValues}.
1958+
18221959
When expected as an input, list values are accepted only when each item in the
18231960
list can be accepted by the list's item type.
18241961

1825-
If the value passed as an input to a list type is _not_ a list and not the
1826-
{null} value, then the result of input coercion is a list of size one, where the
1827-
single item value is the result of input coercion for the list's item type on
1828-
the provided value (note this may apply recursively for nested lists).
1962+
If the value passed as an input to a list type is _not_ a list (and not the
1963+
{null} value), then the result of input coercion is a list of size one, where
1964+
the single item value is the result of input coercion for the list's item type
1965+
on the provided value (which may apply recursively for nested lists).
18291966

18301967
This allows inputs which accept one or many arguments (sometimes referred to as
18311968
"var args") to declare their input type as a list while for the common case of a
18321969
single value, a client can just pass that value directly rather than
18331970
constructing the list.
18341971

1972+
Variables provided as items within a list are resolved to their coerced runtime
1973+
value if provided, otherwise {null} is used in place of an unprovided value.
1974+
18351975
Following are examples of input coercion with various list types and values:
18361976

18371977
| Expected Type | Provided Value | Coerced Value |
@@ -1884,14 +2024,14 @@ within the Execution section.
18842024

18852025
**Input Coercion**
18862026

1887-
If an argument or input-object field of a Non-Null type is not provided, is
1888-
provided with the literal value {null}, or is provided with a variable that was
1889-
either not provided a value at runtime, or was provided the value {null}, then a
1890-
_request error_ must be raised.
2027+
Non-null inputs are _required_, if an argument, variable, or input-object field
2028+
of a Non-Null type is not provided, is provided with the literal value {null},
2029+
or is provided with a variable that was either not provided a value at runtime,
2030+
or was provided the value {null}, it results in a _coercion failure_.
18912031

18922032
If the value provided to the Non-Null type is provided with a literal value
18932033
other than {null}, or a Non-Null variable value, it is coerced using the input
1894-
coercion for the wrapped type.
2034+
coercion for the wrapped type (see {CoerceInputValue()}).
18952035

18962036
A non-null argument cannot be omitted:
18972037

0 commit comments

Comments
 (0)