Skip to content

Commit 3346994

Browse files
committed
Spec edits for incremental delivery, Validation
1 parent b9d8e8a commit 3346994

1 file changed

Lines changed: 179 additions & 0 deletions

File tree

spec/Section 5 -- Validation.md

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ FieldsInSetCanMerge(set):
560560
{set} including visiting fragments and inline fragments.
561561
- Given each pair of distinct members {fieldA} and {fieldB} in {fieldsForName}:
562562
- {SameResponseShape(fieldA, fieldB)} must be true.
563+
- {SameStreamDirective(fieldA, fieldB)} must be true.
563564
- If the parent types of {fieldA} and {fieldB} are equal or if either is not
564565
an Object Type:
565566
- {fieldA} and {fieldB} must have identical field names.
@@ -595,6 +596,16 @@ SameResponseShape(fieldA, fieldB):
595596
- If {SameResponseShape(subfieldA, subfieldB)} is {false}, return {false}.
596597
- Return {true}.
597598

599+
SameStreamDirective(fieldA, fieldB):
600+
601+
- If neither {fieldA} nor {fieldB} has a directive named `stream`.
602+
- Return {true}.
603+
- If both {fieldA} and {fieldB} have a directive named `stream`.
604+
- Let {streamA} be the directive named `stream` on {fieldA}.
605+
- Let {streamB} be the directive named `stream` on {fieldB}.
606+
- If {streamA} and {streamB} have identical sets of arguments, return {true}.
607+
- Return {false}.
608+
598609
Note: In prior versions of the spec the term "composite" was used to signal a
599610
type that is either an Object, Interface or Union type.
600611

@@ -1695,6 +1706,174 @@ query ($foo: Boolean = true, $bar: Boolean = false) {
16951706
}
16961707
```
16971708

1709+
### Defer And Stream Directives Are Used On Valid Root Field
1710+
1711+
** Formal Specification **
1712+
1713+
- For every {directive} in a document.
1714+
- Let {directiveName} be the name of {directive}.
1715+
- Let {mutationType} be the root Mutation type in {schema}.
1716+
- Let {subscriptionType} be the root Subscription type in {schema}.
1717+
- If {directiveName} is "defer" or "stream":
1718+
- The parent type of {directive} must not be {mutationType} or
1719+
{subscriptionType}.
1720+
1721+
**Explanatory Text**
1722+
1723+
The defer and stream directives are not allowed to be used on root fields of the
1724+
mutation or subscription type.
1725+
1726+
For example, the following document will not pass validation because `@defer`
1727+
has been used on a root mutation field:
1728+
1729+
```raw graphql counter-example
1730+
mutation {
1731+
... @defer {
1732+
mutationField
1733+
}
1734+
}
1735+
```
1736+
1737+
### Defer And Stream Directives Are Used On Valid Operations
1738+
1739+
** Formal Specification **
1740+
1741+
- Let {subscriptionFragments} be the empty set.
1742+
- For each {operation} in a document:
1743+
- If {operation} is a subscription operation:
1744+
- Let {fragments} be every fragment referenced by that {operation}
1745+
transitively.
1746+
- For each {fragment} in {fragments}:
1747+
- Let {fragmentName} be the name of {fragment}.
1748+
- Add {fragmentName} to {subscriptionFragments}.
1749+
- For every {directive} in a document:
1750+
- If {directiveName} is not "defer" or "stream":
1751+
- Continue to the next {directive}.
1752+
- Let {ancestor} be the ancestor operation or fragment definition of
1753+
{directive}.
1754+
- If {ancestor} is a fragment definition:
1755+
- If the fragment name of {ancestor} is not present in
1756+
{subscriptionFragments}:
1757+
- Continue to the next {directive}.
1758+
- If {ancestor} is not a subscription operation:
1759+
- Continue to the next {directive}.
1760+
- Let {if} be the argument named "if" on {directive}.
1761+
- {if} must be defined.
1762+
- Let {argumentValue} be the value passed to {if}.
1763+
- {argumentValue} must be a variable, or the boolean value "false".
1764+
1765+
**Explanatory Text**
1766+
1767+
The defer and stream directives can not be used to defer or stream data in
1768+
subscription operations. If these directives appear in a subscription operation
1769+
they must be disabled using the "if" argument. This rule will not permit any
1770+
defer or stream directives on a subscription operation that cannot be disabled
1771+
using the "if" argument.
1772+
1773+
For example, the following document will not pass validation because `@defer`
1774+
has been used in a subscription operation with no "if" argument defined:
1775+
1776+
```raw graphql counter-example
1777+
subscription sub {
1778+
newMessage {
1779+
... @defer {
1780+
body
1781+
}
1782+
}
1783+
}
1784+
```
1785+
1786+
### Defer And Stream Directive Labels Are Unique
1787+
1788+
** Formal Specification **
1789+
1790+
- Let {labelValues} be an empty set.
1791+
- For every {directive} in the document:
1792+
- Let {directiveName} be the name of {directive}.
1793+
- If {directiveName} is "defer" or "stream":
1794+
- For every {argument} in {directive}:
1795+
- Let {argumentName} be the name of {argument}.
1796+
- Let {argumentValue} be the value passed to {argument}.
1797+
- If {argumentName} is "label":
1798+
- {argumentValue} must not be a variable.
1799+
- {argumentValue} must not be present in {labelValues}.
1800+
- Append {argumentValue} to {labelValues}.
1801+
1802+
**Explanatory Text**
1803+
1804+
The `@defer` and `@stream` directives each accept an argument "label". This
1805+
label may be used by GraphQL clients to uniquely identify response payloads. If
1806+
a label is passed, it must not be a variable and it must be unique within all
1807+
other `@defer` and `@stream` directives in the document.
1808+
1809+
For example the following document is valid:
1810+
1811+
```graphql example
1812+
{
1813+
dog {
1814+
...fragmentOne
1815+
...fragmentTwo @defer(label: "dogDefer")
1816+
}
1817+
pets @stream(label: "petStream") {
1818+
name
1819+
}
1820+
}
1821+
1822+
fragment fragmentOne on Dog {
1823+
name
1824+
}
1825+
1826+
fragment fragmentTwo on Dog {
1827+
owner {
1828+
name
1829+
}
1830+
}
1831+
```
1832+
1833+
For example, the following document will not pass validation because the same
1834+
label is used in different `@defer` and `@stream` directives.:
1835+
1836+
```raw graphql counter-example
1837+
{
1838+
dog {
1839+
...fragmentOne @defer(label: "MyLabel")
1840+
}
1841+
pets @stream(label: "MyLabel") {
1842+
name
1843+
}
1844+
}
1845+
1846+
fragment fragmentOne on Dog {
1847+
name
1848+
}
1849+
```
1850+
1851+
### Stream Directives Are Used On List Fields
1852+
1853+
**Formal Specification**
1854+
1855+
- For every {directive} in a document.
1856+
- Let {directiveName} be the name of {directive}.
1857+
- If {directiveName} is "stream":
1858+
- Let {adjacent} be the AST node the directive affects.
1859+
- {adjacent} must be a List type.
1860+
1861+
**Explanatory Text**
1862+
1863+
GraphQL directive locations do not provide enough granularity to distinguish the
1864+
type of fields used in a GraphQL document. Since the stream directive is only
1865+
valid on list fields, an additional validation rule must be used to ensure it is
1866+
used correctly.
1867+
1868+
For example, the following document will only pass validation if `field` is
1869+
defined as a List type in the associated schema.
1870+
1871+
```graphql counter-example
1872+
query {
1873+
field @stream(initialCount: 0)
1874+
}
1875+
```
1876+
16981877
## Variables
16991878

17001879
### Variable Uniqueness

0 commit comments

Comments
 (0)