Skip to content

Commit be33a64

Browse files
OlegIlyenkoleebyronspawnia
committed
[RFC] Repeatable directives (#472)
* Limit directive uniqueness to explicitly marked directives * Mark `@skip`. `@include` and `@deprecated` as unique * Use `repeatable` instead of `unique` keyword. Also changed the default. * Rename `repeatable` → `isRepeatable` in the introspection * Improved repeatable directive example * Better description for `repeatable` directives * Improved `repeatable` directive description * Apply suggestions from code review * Editorial Co-authored-by: Lee Byron <[email protected]> Co-authored-by: Benedikt Franke <[email protected]>
1 parent 39f7a34 commit be33a64

File tree

4 files changed

+40
-10
lines changed

4 files changed

+40
-10
lines changed

spec/Appendix B -- Grammar Summary.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ InputObjectTypeExtension :
302302
- extend input Name Directives[Const]? InputFieldsDefinition
303303
- extend input Name Directives[Const]
304304

305-
DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? on DirectiveLocations
305+
DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? `repeatable`? on DirectiveLocations
306306

307307
DirectiveLocations :
308308
- DirectiveLocations | DirectiveLocation

spec/Section 3 -- Type System.md

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ adds additional operation types, or additional directives to an existing schema.
165165
Schema extensions have the potential to be invalid if incorrectly defined.
166166

167167
1. The Schema must already be defined.
168-
2. Any directives provided must not already apply to the original Schema.
168+
2. Any non-repeatable directives provided must not already apply to the
169+
original Schema.
169170

170171

171172
## Descriptions
@@ -549,7 +550,8 @@ GraphQL tool or service which adds directives to an existing scalar.
549550
Scalar type extensions have the potential to be invalid if incorrectly defined.
550551

551552
1. The named type must already be defined and must be a Scalar type.
552-
2. Any directives provided must not already apply to the original Scalar type.
553+
2. Any non-repeatable directives provided must not already apply to the
554+
original Scalar type.
553555

554556

555557
## Objects
@@ -939,7 +941,8 @@ Object type extensions have the potential to be invalid if incorrectly defined.
939941
may share the same name.
940942
3. Any fields of an Object type extension must not be already defined on the
941943
original Object type.
942-
4. Any directives provided must not already apply to the original Object type.
944+
4. Any non-repeatable directives provided must not already apply to the
945+
original Object type.
943946
5. Any interfaces provided must not be already implemented by the original
944947
Object type.
945948
6. The resulting extended object type must be a super-set of all interfaces it
@@ -1121,7 +1124,8 @@ Interface type extensions have the potential to be invalid if incorrectly define
11211124
4. Any Object type which implemented the original Interface type must also be a
11221125
super-set of the fields of the Interface type extension (which may be due to
11231126
Object type extension).
1124-
5. Any directives provided must not already apply to the original Interface type.
1127+
5. Any non-repeatable directives provided must not already apply to the
1128+
original Interface type.
11251129

11261130

11271131
## Unions
@@ -1244,7 +1248,8 @@ Union type extensions have the potential to be invalid if incorrectly defined.
12441248
3. All member types of a Union type extension must be unique.
12451249
4. All member types of a Union type extension must not already be a member of
12461250
the original Union type.
1247-
5. Any directives provided must not already apply to the original Union type.
1251+
5. Any non-repeatable directives provided must not already apply to the
1252+
original Union type.
12481253

12491254
## Enums
12501255

@@ -1313,7 +1318,8 @@ Enum type extensions have the potential to be invalid if incorrectly defined.
13131318
2. All values of an Enum type extension must be unique.
13141319
3. All values of an Enum type extension must not already be a value of
13151320
the original Enum.
1316-
4. Any directives provided must not already apply to the original Enum type.
1321+
4. Any non-repeatable directives provided must not already apply to the
1322+
original Enum type.
13171323

13181324

13191325
## Input Objects
@@ -1442,7 +1448,8 @@ Input object type extensions have the potential to be invalid if incorrectly def
14421448
3. All fields of an Input Object type extension must have unique names.
14431449
4. All fields of an Input Object type extension must not already be a field of
14441450
the original Input Object.
1445-
5. Any directives provided must not already apply to the original Input Object type.
1451+
5. Any non-repeatable directives provided must not already apply to the
1452+
original Input Object type.
14461453

14471454

14481455
## List
@@ -1611,7 +1618,7 @@ Expected Type | Internal Value | Coerced Result
16111618

16121619
## Directives
16131620

1614-
DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? on DirectiveLocations
1621+
DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? `repeatable`? on DirectiveLocations
16151622

16161623
DirectiveLocations :
16171624
- DirectiveLocations | DirectiveLocation
@@ -1705,12 +1712,31 @@ type SomeType {
17051712
}
17061713
```
17071714

1715+
A directive may be defined as repeatable by including the "repeatable" keyword.
1716+
Repeatable directives are often useful when the same directive should be used
1717+
with different arguments at a single location, especially in cases where
1718+
additional information needs to be provided to a type or schema extension via
1719+
a directive:
1720+
1721+
```graphql example
1722+
directive @delegateField(name: String!) repeatable on OBJECT | INTERFACE
1723+
1724+
type Book @delegateField(name: "pageCount") @delegateField(name: "author") {
1725+
id: ID!
1726+
}
1727+
1728+
extend type Book @delegateField(name: "index")
1729+
```
1730+
17081731
While defining a directive, it must not reference itself directly or indirectly:
17091732

17101733
```graphql counter-example
17111734
directive @invalidExample(arg: String @invalidExample) on ARGUMENT_DEFINITION
17121735
```
17131736

1737+
Note: The order in which directives appear may be significant, including
1738+
repeatable directives.
1739+
17141740
**Validation**
17151741

17161742
1. A directive definition must not contain the use of a directive which

spec/Section 4 -- Introspection.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ type __Directive {
187187
description: String
188188
locations: [__DirectiveLocation!]!
189189
args: [__InputValue!]!
190+
isRepeatable: Boolean!
190191
}
191192

192193
enum __DirectiveLocation {
@@ -417,3 +418,5 @@ Fields
417418
locations this directive may be placed.
418419
* `args` returns a List of `__InputValue` representing the arguments this
419420
directive accepts.
421+
* `isRepeatable` must return a Boolean that indicates if the directive may be
422+
used repeatedly at a single location.

spec/Section 5 -- Validation.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1441,7 +1441,8 @@ query @skip(if: $foo) {
14411441
**Formal Specification**
14421442

14431443
* For every {location} in the document for which Directives can apply:
1444-
* Let {directives} be the set of Directives which apply to {location}.
1444+
* Let {directives} be the set of Directives which apply to {location} and
1445+
are not repeatable.
14451446
* For each {directive} in {directives}:
14461447
* Let {directiveName} be the name of {directive}.
14471448
* Let {namedDirectives} be the set of all Directives named {directiveName}

0 commit comments

Comments
 (0)