Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow unions to declare implementation of interfaces #939

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
79 changes: 68 additions & 11 deletions spec/Section 3 -- Type System.md
Expand Up @@ -1051,7 +1051,9 @@ InterfaceTypeDefinition :

GraphQL interfaces represent a list of named fields and their arguments. GraphQL
objects and interfaces can then implement these interfaces which requires that
the implementing type will define all fields defined by those interfaces.
the implementing type will define all fields defined by those interfaces. Unions
can also implement interfaces, as long as each union member implements those
interfaces.

Fields on a GraphQL interface have the same rules as fields on a GraphQL object;
their type can be Scalar, Object, Enum, Interface, or Union, or any wrapping
Expand Down Expand Up @@ -1144,9 +1146,9 @@ interface. Querying for `age` is only valid when the result of `entity` is a
**Interfaces Implementing Interfaces**

When defining an interface that implements another interface, the implementing
interface must define each field that is specified by the implemented interface.
For example, the interface Resource must define the field id to implement the
Node interface:
type must define each field that is specified by the implemented interface. For
yaacovCR marked this conversation as resolved.
Show resolved Hide resolved
example, the interface Resource must define the field id to implement the Node
interface:

```raw graphql example
interface Node {
Expand All @@ -1160,9 +1162,8 @@ interface Resource implements Node {
```

Transitively implemented interfaces (interfaces implemented by the interface
that is being implemented) must also be defined on an implementing type or
interface. For example, `Image` cannot implement `Resource` without also
implementing `Node`:
that is being implemented) must also be defined on the implementing type. For
example, `Image` cannot implement `Resource` without also implementing `Node`:

```raw graphql example
interface Node {
Expand All @@ -1181,6 +1182,8 @@ interface Image implements Resource & Node {
}
```

Similar syntax for unions implementing interfaces is detailed below.

Interface definitions must not contain cyclic references nor implement
themselves. This example is invalid because `Node` and `Named` implement
themselves and each other:
Expand Down Expand Up @@ -1293,8 +1296,8 @@ defined.

## Unions

UnionTypeDefinition : Description? union Name Directives[Const]?
UnionMemberTypes?
UnionTypeDefinition : Description? union Name ImplementsInterfaces?
Directives[Const]? UnionMemberTypes?

UnionMemberTypes :

Expand Down Expand Up @@ -1370,6 +1373,50 @@ union SearchResult =
| Person
```

**Unions Implementing Interfaces**

When defining unions that implement interfaces, each union member must
explicitly implement each interface implemented by the union. For example, the
member types of union SearchResult must each explicitly implement the Resource
interface:

```raw graphql example
interface Resource {
url: String
}

union SearchResult implements Resource = Photo | Article
yaacovCR marked this conversation as resolved.
Show resolved Hide resolved

type Article implements Resource {
url: String
title: String
}

type Image implements Resource {
url: String
height: Int
width: Int
}
```

Transitively implemented interfaces (interfaces implemented by the interface
that is being implemented) must also be defined on the implementing union. For
example, `SearchResult` cannot implement `Resource` without also implementing
`Node`:

```raw graphql example
interface Node {
id: ID!
}

interface Resource implements Node {
id: ID!
url: String
}

union SearchResult implements Resource & Node = Photo | Article
```

**Result Coercion**

The union type should have some way of determining which object a given result
Expand All @@ -1388,13 +1435,21 @@ Union types have the potential to be invalid if incorrectly defined.
2. The member types of a Union type must all be Object base types; Scalar,
Interface and Union types must not be member types of a Union. Similarly,
wrapping types must not be member types of a Union.
3. An union type may declare that it implements one or more unique interfaces.
yaacovCR marked this conversation as resolved.
Show resolved Hide resolved
4. Each member of a union must be a super-set of all union-implemented
interfaces:
1. Let this union type be {implementingType}.
2. For each member type of {implementingType}:
1. Let this member type be {memberType}.
2. For each interface declared implemented as {implementedType},
{IsValidImplementation(memberType, implementedType)} must be {true}.

### Union Extensions

UnionTypeExtension :

- extend union Name Directives[Const]? UnionMemberTypes
- extend union Name Directives[Const]
- extend union Name ImplementsInterfaces? Directives[Const]? UnionMemberTypes
- extend union Name ImplementsInterfaces? Directives[Const]

Union type extensions are used to represent a union type which has been extended
from some original union type. For example, this might be used to represent
Expand All @@ -1414,6 +1469,8 @@ Union type extensions have the potential to be invalid if incorrectly defined.
the original Union type.
5. Any non-repeatable directives provided must not already apply to the original
Union type.
6. All member types of the resulting extended Union type must be a super-set of
all Interfaces it implements.

## Enums

Expand Down