Skip to content

Interface conditions fragments may not be used across spreads, discouraging reusability #1085

Open
@duckki

Description

@duckki

(This idea was inspired by apollographql/federation#2952 .)

Motivating example

Schema:

type A {
    f(arg:String!): String!
}

interface I {
    id: ID!
    f(arg:String!): String!
}

type B implements I {
    id: ID!
    f(arg:String!): String!
}

type C implements I {
    id: ID!
    f(arg:String!): String!
}

union U = A | B | C

type Query {
    get: U!
}

Accepted query:

query Ok {
    get {
        ...on A {
            f(arg: "a")
        }
        ...on B {
            f(arg: "b") # no problem
        }
        ...on C {
            f(arg: "b") # no problem
        }
    }
}

Rejected query:

# A fragment that works on any types implementing I.
fragment genericFragment on I {
    f(arg: "b")
}

query ValidationRejected {
    get {
        ...on A {
            f(arg: "a")
        }
        ...on B {
            ...genericFragment # rejected
        }
        ...on C {
            ...genericFragment # rejected
        }
    }
}

This query is rejected by GraphQL.js's validator, complaining that f(arg: "a") and f(arg: "b") are conflicting.

This is disappointing because it discourages using interface-conditioned fragments like genericFragment above under a more derived type context (like ...on B).

Potential improvement in FieldsInSetCanMerge(set)

The current FieldsInSetCanMerge rule only looks at the (immediate) parent type of fields when checking if they can merge.

  • If the parent types of {fieldA} and {fieldB} are equal or if either is not an Object Type:
    ...

I propose to change FieldsInSetCanMerge rule to check:

  • If the context types of fieldA and fieldB has non-empty intersection:

where

  • The context type is defined as the most derived type deduced for the current context. This is new, but it won't be difficult to implement in validators.
  • The intersection of two types A and B means the intersection of GetPossibleTypes(A) and GetPossibleTypes(B) as in the Fragment Spread Is Possible section of the spec.

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