Skip to content

Open question I stumbled across while implementing feddi-gateway #222

Description

@andimarek

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

  1. Does External Unused count @key references, @require references, or
    only @provides references?
  2. If only @provides counts, should the External Argument * rules be removed
    or narrowed to key fields?
  3. If @key counts, are argument-bearing external key fields allowed when the
    key supplies constant arguments?
  4. 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

  1. Is @require on an interface field argument supported?
  2. If supported, is the requirement inherited by all implementing object fields?
  3. If not inherited, must every implementing object repeat the same @require
    on the corresponding argument?
  4. 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?
  5. 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

  1. For @require, must a non-null argument be derivable for every possible
    concrete runtime type of the root object?
  2. If an argument is nullable, is an uncovered runtime type treated as null,
    or is it still a composition error?
  3. For nested input objects, does the coverage rule apply recursively to each
    non-null input field?
  4. For @is, is partial coverage intentionally allowed so that one lookup can
    support only a subset of an abstract type's possible runtime objects?
  5. 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

  1. Is @require always invalid on a lookup field argument?
  2. If not always invalid, is it only valid for nested lookup fields where a
    parent object context exists?
  3. How does an argument with both @is and @require contribute to
    LookupPathSets?
  4. If a lookup argument has @require, is it removed from the composite schema
    like other required arguments?
  5. 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

  1. Should External Unused be changed so an @external field is valid when it
    is referenced by either @key or @provides?
  2. Are external key fields directly queryable through the source schema that
    marks them external, or only through another source schema that owns them?
  3. 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?
  4. Does External Missing on Base always require a non-external counterpart for
    an external key field?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions