Hey folks,
while I was Implementing https://github.com/feddi-dev/feddi-gateway/ I came across a couple of unclear aspects of the spec. Here is a summary of each question + relevant links.
There are often multiple relevant links/issues for each problem, so I decided to open this summary for now.
Summary
| Topic |
Current status |
@external with argument-bearing fields |
Ambiguous. The draft validates arguments on @external fields, but @provides cannot reference fields with arguments. |
@require on interface fields |
Underspecified. The directive is not forbidden on interface field arguments, but inheritance and object/interface merge behavior are not defined clearly enough. |
Type-condition coverage in @require and @is |
Underspecified. The draft validates that type references are possible, not that alternatives cover every runtime type. |
@require on @lookup arguments |
Underspecified. The draft does not forbid it, and issue/PR discussion suggests possible future nested-lookup use cases, but the current algorithms do not define it. |
@external key fields without @provides |
Partially clarified. The source-schema section explicitly allows @external for key fields, but the External Unused validation rule still only mentions @provides. |
1. @external and @provides on Fields With Arguments
Relevant Spec Sections
Problem
The current draft says an @external field is recognized by a source schema but
not directly resolved by it. It also says such a field may be referenced for
entity identification through @key or for field provision through
@provides.
The ambiguity is in the validation rules:
External Unused says every @external field must be referenced by
@provides.
Provides Fields Has Arguments says a @provides(fields: ...) selection must
not reference a field that has arguments.
- The
External Argument * rules validate argument default values, missing
arguments, and argument type mismatches on @external fields, which strongly
implies that argument-bearing @external fields are representable.
@key, @is, and @require can use constant arguments in their
FieldSelectionMap/field selection syntax, while @provides explicitly
cannot.
That leaves an unreachable state for an argument-bearing @external field that
is not used by @key: it appears valid enough to have argument validation
rules, but invalid because it cannot be referenced by the only use counted by
External Unused.
Relevant Issues and PRs
Questions to Resolve
- Does
External Unused count @key references, @require references, or
only @provides references?
- If only
@provides counts, should the External Argument * rules be removed
or narrowed to key fields?
- If
@key counts, are argument-bearing external key fields allowed when the
key supplies constant arguments?
- Is there any intended legal use for an argument-bearing external field that
is neither a key field nor referenced by @require/@is?
2. @require on Interface Fields
Relevant Spec Sections
Problem
The draft defines @require on ARGUMENT_DEFINITION. The validation algorithm
walks arguments on all composite types, and in this spec "composite types" are
object and interface types. The draft does not explicitly forbid @require on
arguments of interface fields.
The difficulty is the interaction with GraphQL's interface contract and the
composition merge process:
- In GraphQL, an object field implementing an interface field must be compatible
with the interface field, including its arguments.
@require removes the annotated argument from the composite schema.
- The merge algorithm filters out arguments marked with
@require before field
arguments are merged.
- The spec does not say whether an object implementation inherits an interface
field argument's @require directive, must repeat it, or may omit it.
- The spec explicitly forbids
@external on interface fields because interface
fields are abstract, but it does not apply the same reasoning to @require.
Relevant Issues and PRs
No directly matching issue was found for "@require on interface field
arguments" specifically. The relevant issue/PR history is broader interface
merge behavior.
Questions to Resolve
- Is
@require on an interface field argument supported?
- If supported, is the requirement inherited by all implementing object fields?
- If not inherited, must every implementing object repeat the same
@require
on the corresponding argument?
- If only the object field has
@require, does the interface field still need
to declare the argument in the source schema, and is it removed from the
composite schema?
- Can a
FieldSelectionMap used by an interface field's @require reference
concrete implementing types through type conditions?
3. Type-Condition Coverage in @require and @is
Relevant Spec Sections
Problem
The current draft validates that a type reference in a FieldSelectionMap is
possible in the current context. It does this by checking that the possible
types of the referenced type and the parent type intersect.
That is not the same as coverage. For an abstract parent type, the draft does
not say that all possible concrete runtime types must be covered by the
alternatives in a FieldSelectionMap.
Example:
interface Media @key(fields: "id") {
id: ID!
}
type Movie implements Media @key(fields: "id") {
id: ID!
imdbCode: String
}
type TVShow implements Media @key(fields: "id") {
id: ID!
tvdbCode: String
}
type Podcast implements Media @key(fields: "id") {
id: ID!
rssUrl: String
}
type Movie @key(fields: "id") {
id: ID!
similar(code: String! @require(field: "<Movie>.imdbCode | <TVShow>.tvdbCode")): [Movie]
}
<Movie> and <TVShow> are possible type references, but Podcast is not
covered. For @require, that matters because the distributed executor must
synthesize the code argument. If the runtime object is a Podcast, no
selected value exists. For a non-null argument, this cannot be represented as a
valid input value.
The spec has related validation for required input object fields, but that only
checks whether required input fields are present in the selected object
structure. It does not say that each selected field must be producible for every
possible runtime object type.
The satisfiability section models alternatives as path-set alternatives and
requires at least one alternative to resolve. That is useful for planning, but
still does not define a nullability-sensitive coverage rule.
Relevant Issues and PRs
No directly matching issue was found for "every concrete type must be covered by
@require alternatives". The closest discussions are about type-reference
validity, nullability, and satisfiability.
Questions to Resolve
- For
@require, must a non-null argument be derivable for every possible
concrete runtime type of the root object?
- If an argument is nullable, is an uncovered runtime type treated as
null,
or is it still a composition error?
- For nested input objects, does the coverage rule apply recursively to each
non-null input field?
- For
@is, is partial coverage intentionally allowed so that one lookup can
support only a subset of an abstract type's possible runtime objects?
- If no type-condition alternative matches at runtime, is the behavior a
planned null, a request error, an execution error, or undefined behavior?
4. @require on @lookup Field Arguments
Relevant Spec Sections
Problem
The current draft explicitly says @is belongs on arguments of @lookup
fields. The Is Invalid Usage rule rejects @is on an argument whose declaring
field is not a lookup field.
There is no corresponding Require Invalid Usage rule. The spec does not
explicitly forbid:
type Query {
productById(
id: ID!
locale: String! @require(field: "defaultLocale")
): Product @lookup
}
However, the execution model is not defined for that shape:
- A root
@lookup field is used to obtain an entity. A @require argument
needs data from an existing entity context. For a root lookup, that is a
chicken-and-egg problem.
- The satisfiability algorithm's
LookupPathSets step describes lookup inputs
using @is or the argument name. It does not define how an argument annotated
with @require contributes to lookup input requirements.
@require removes annotated arguments from the composite schema. The spec
does not say whether a lookup argument with @require is callable by clients,
internal to the executor, or both invalid and removed.
Relevant Issues and PRs
Questions to Resolve
- Is
@require always invalid on a lookup field argument?
- If not always invalid, is it only valid for nested lookup fields where a
parent object context exists?
- How does an argument with both
@is and @require contribute to
LookupPathSets?
- If a lookup argument has
@require, is it removed from the composite schema
like other required arguments?
- What error code should be produced for invalid root-lookup usage?
5. @external Without @provides on Key Fields
Relevant Spec Sections
Problem
The current draft's @external section explicitly includes key usage:
type Query {
productBySku(sku: String!): Product @lookup
productByUpc(upc: String!): Product @lookup
}
type Product @key(fields: "sku") @key(fields: "upc") {
sku: String! @external
upc: String! @external
name: String
}
The same section says an external field is referenced only for entity
identification via @key or for providing a field through @provides.
That clarifies intent: an external key field without @provides is meant to be
valid if the key reference is the reason the field exists locally.
The remaining conflict is normative validation text. External Unused still
says every @external field must be referenced by @provides; it does not say
that a @key reference also counts.
There is also a query-planning question. If a source schema returns an entity
whose local key field is marked @external, that source schema cannot resolve
the key field locally. A client selection of that key field is only satisfiable
if the planner can move to another source schema that provides it. If the key
field is also needed to perform that move and is not available in the current
result, the path is unsatisfiable.
Relevant Issues and PRs
Questions to Resolve
- Should
External Unused be changed so an @external field is valid when it
is referenced by either @key or @provides?
- Are external key fields directly queryable through the source schema that
marks them external, or only through another source schema that owns them?
- If an external key field is required to move from the current source schema
to another source schema, what guarantees that the current source schema has
the key value available at runtime?
- Does
External Missing on Base always require a non-external counterpart for
an external key field?
Hey folks,
while I was Implementing https://github.com/feddi-dev/feddi-gateway/ I came across a couple of unclear aspects of the spec. Here is a summary of each question + relevant links.
There are often multiple relevant links/issues for each problem, so I decided to open this summary for now.
Summary
@externalwith argument-bearing fields@externalfields, but@providescannot reference fields with arguments.@requireon interface fields@requireand@is@requireon@lookuparguments@externalkey fields without@provides@externalfor key fields, but theExternal Unusedvalidation rule still only mentions@provides.1.
@externaland@provideson Fields With ArgumentsRelevant Spec Sections
@externalExternal UnusedProvides Fields Has ArgumentsExternal Argument Default MismatchExternal Argument MissingExternal Argument Type Mismatch@key@is@requireProblem
The current draft says an
@externalfield is recognized by a source schema butnot directly resolved by it. It also says such a field may be referenced for
entity identification through
@keyor for field provision through@provides.The ambiguity is in the validation rules:
External Unusedsays every@externalfield must be referenced by@provides.Provides Fields Has Argumentssays a@provides(fields: ...)selection mustnot reference a field that has arguments.
External Argument *rules validate argument default values, missingarguments, and argument type mismatches on
@externalfields, which stronglyimplies that argument-bearing
@externalfields are representable.@key,@is, and@requirecan use constant arguments in theirFieldSelectionMap/field selection syntax, while@providesexplicitlycannot.
That leaves an unreachable state for an argument-bearing
@externalfield thatis not used by
@key: it appears valid enough to have argument validationrules, but invalid because it cannot be referenced by the only use counted by
External Unused.Relevant Issues and PRs
@externalwork exactlyis open and tracks the different meanings of
@external, including keyfields,
@provides,@requires/@require-like use cases, andinterface-satisfaction cases.
External Unusedrule lacks complex examplesis open and points out that the rule does not explain nested selections or
abstract-type fragments in
@provides.introduced the external validation rules.
@externaldirective spec textintroduced source-schema text for
@external.and PR #205: Rearrange directive collision rules
split collision rules such as
EXTERNAL_PROVIDES_COLLISIONandEXTERNAL_REQUIRE_COLLISION, but did not resolve the argument-bearing@externaluse case.Questions to Resolve
External Unusedcount@keyreferences,@requirereferences, oronly
@providesreferences?@providescounts, should theExternal Argument *rules be removedor narrowed to key fields?
@keycounts, are argument-bearing external key fields allowed when thekey supplies constant arguments?
is neither a key field nor referenced by
@require/@is?2.
@requireon Interface FieldsRelevant Spec Sections
@requireRequire Invalid FieldsExternal on InterfaceMerge Output FieldsInterface Field No ImplementationType Reference Is PossibleProblem
The draft defines
@requireonARGUMENT_DEFINITION. The validation algorithmwalks arguments on all composite types, and in this spec "composite types" are
object and interface types. The draft does not explicitly forbid
@requireonarguments of interface fields.
The difficulty is the interaction with GraphQL's interface contract and the
composition merge process:
with the interface field, including its arguments.
@requireremoves the annotated argument from the composite schema.@requirebefore fieldarguments are merged.
field argument's
@requiredirective, must repeat it, or may omit it.@externalon interface fields because interfacefields are abstract, but it does not apply the same reasoning to
@require.Relevant Issues and PRs
is open and says interface merge behavior currently creates coupling because
implementing types must provide required fields.
is open and confirms that merging the
implementspart of objects andinterfaces is not fully specified.
is open and includes interface validation concerns, including that interface
algorithms are wrong or unclear in the current draft.
@externalwork exactlyincludes an interface-satisfaction use case for
@external, showing thatinterface-local versus implementation-local ownership is still under
discussion.
No directly matching issue was found for "
@requireon interface fieldarguments" specifically. The relevant issue/PR history is broader interface
merge behavior.
Questions to Resolve
@requireon an interface field argument supported?@requireon the corresponding argument?
@require, does the interface field still needto declare the argument in the source schema, and is it removed from the
composite schema?
FieldSelectionMapused by an interface field's@requirereferenceconcrete implementing types through type conditions?
3. Type-Condition Coverage in
@requireand@isRelevant Spec Sections
FieldSelectionMapappendixType Reference Is PossibleRequired Selected Object FieldsIs Invalid FieldsRequire Invalid FieldsUnsatisfiable Query PathProblem
The current draft validates that a type reference in a
FieldSelectionMapispossible in the current context. It does this by checking that the possible
types of the referenced type and the parent type intersect.
That is not the same as coverage. For an abstract parent type, the draft does
not say that all possible concrete runtime types must be covered by the
alternatives in a
FieldSelectionMap.Example:
<Movie>and<TVShow>are possible type references, butPodcastis notcovered. For
@require, that matters because the distributed executor mustsynthesize the
codeargument. If the runtime object is aPodcast, noselected value exists. For a non-null argument, this cannot be represented as a
valid input value.
The spec has related validation for required input object fields, but that only
checks whether required input fields are present in the selected object
structure. It does not say that each selected field must be producible for every
possible runtime object type.
The satisfiability section models alternatives as path-set alternatives and
requires at least one alternative to resolve. That is useful for planning, but
still does not define a nullability-sensitive coverage rule.
Relevant Issues and PRs
is open and specifically calls out confusing terminology in
Type Reference Is Possible, missing examples, and unclear nullabilityhandling in
Values of Correct Type.* Invalid Fieldsto work with the composite schemais open and questions the feasibility and shape of the
Is Invalid Fields,Key Invalid Fields, andRequire Invalid Fieldsalgorithms.@iswas closed by PR #190: Add validation rules for
@is.This added
@isvalidation rules, but did not define abstract-type coverage.is open and covers adjacent satisfiability concerns for abstract runtime
types.
was closed after Appendix A introduced
FieldSelectionMap.introduced the field-selection appendix.
No directly matching issue was found for "every concrete type must be covered by
@requirealternatives". The closest discussions are about type-referencevalidity, nullability, and satisfiability.
Questions to Resolve
@require, must a non-null argument be derivable for every possibleconcrete runtime type of the root object?
null,or is it still a composition error?
non-null input field?
@is, is partial coverage intentionally allowed so that one lookup cansupport only a subset of an abstract type's possible runtime objects?
planned
null, a request error, an execution error, or undefined behavior?4.
@requireon@lookupField ArgumentsRelevant Spec Sections
@lookup@is@requireIs Invalid UsageRequire Invalid FieldsUnsatisfiable Query PathProblem
The current draft explicitly says
@isbelongs on arguments of@lookupfields. The
Is Invalid Usagerule rejects@ison an argument whose declaringfield is not a lookup field.
There is no corresponding
Require Invalid Usagerule. The spec does notexplicitly forbid:
However, the execution model is not defined for that shape:
@lookupfield is used to obtain an entity. A@requireargumentneeds data from an existing entity context. For a root lookup, that is a
chicken-and-egg problem.
LookupPathSetsstep describes lookup inputsusing
@isor the argument name. It does not define how an argument annotatedwith
@requirecontributes to lookup input requirements.@requireremoves annotated arguments from the composite schema. The specdoes not say whether a lookup argument with
@requireis callable by clients,internal to the executor, or both invalid and removed.
Relevant Issues and PRs
clarified that lookup and key are separate concepts. Its discussion includes
possible nested lookup designs where
@isand@requiremight both appear onlookup arguments, but the merged spec does not define that syntax.
@lookupand@keymatchwas closed as no longer relevant.
@lookupin invalid locationis open, but it is about invalid directive location, not
@requireon lookuparguments.
@requirethat specify argumentsis open and shows that
@requireover argument-bearing referenced fields isstill under discussion.
was closed after broader satisfiability rules were added, but the discussion
shows that lookup, require, and provides planning rules were being separated
iteratively.
Questions to Resolve
@requirealways invalid on a lookup field argument?parent object context exists?
@isand@requirecontribute toLookupPathSets?@require, is it removed from the composite schemalike other required arguments?
5.
@externalWithout@provideson Key FieldsRelevant Spec Sections
@external@keyExternal UnusedExternal Missing on BaseUnsatisfiable Query PathProblem
The current draft's
@externalsection explicitly includes key usage:The same section says an external field is referenced only for entity
identification via
@keyor for providing a field through@provides.That clarifies intent: an external key field without
@providesis meant to bevalid if the key reference is the reason the field exists locally.
The remaining conflict is normative validation text.
External Unusedstillsays every
@externalfield must be referenced by@provides; it does not saythat a
@keyreference also counts.There is also a query-planning question. If a source schema returns an entity
whose local key field is marked
@external, that source schema cannot resolvethe key field locally. A client selection of that key field is only satisfiable
if the planner can move to another source schema that provides it. If the key
field is also needed to perform that move and is not available in the current
result, the path is unsatisfiable.
Relevant Issues and PRs
@externalwork exactlyis open and includes discussion of key fields marked
@external, includingwhether that makes them unresolvable in the current subgraph.
External Unusedrule lacks complex examplesis open and shows that
External Unuseddoes not yet fully describe complexexternal references.
@externaldirective spec textadded the source-schema text that includes key-field usage.
@externaldirectives to examplesadjusted examples to include missing
@externaldirectives, reinforcing thatexamples are still being aligned with the validation rules.
clarified lookup/key relationships, which matters because key fields and
lookup inputs overlap but are not identical concepts.
@lookupand@keymatchwas closed as no longer relevant.
Questions to Resolve
External Unusedbe changed so an@externalfield is valid when itis referenced by either
@keyor@provides?marks them external, or only through another source schema that owns them?
to another source schema, what guarantees that the current source schema has
the key value available at runtime?
External Missing on Basealways require a non-external counterpart foran external key field?