graphql / graphql/graphql-spec

Improve support for covariance in interfaces with field selection merging

Open
#804 1 comment 9 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
14.6k
Forks
1.2k
PR merge metrics
No merged PRs in 30d

Description

I'm not sure the best way to talk about a possible solution for this one, but I'll try and illustration the problem.

## Use case: Draft/Published implementations of an interface

I'm fond of using interfaces to model state machines in GraphQL. A very simple example would be a blog post which can be in either a draft or published state. I can model it as such (this is a simplified scenario):

```graphql
interface Post {
id: ID!
title: String
body: String
}

type DraftPost implements Post {
id: ID!
title: String
body: String
}

type PublishedPost implements Post {
id: ID!
title: String!
body: String!
}
```

Key thing here is that `PublishedPost` and `DraftPost` are the same except for the fact that all the fields are now required on `PublishedPost`. Even though PublishedPost is redefining/overriding fields declared on the interface, this is a valid schema because a field being required is a refinement of an optional field, and GraphQL allows covariance for return types.

A problem i've run into is when constructing a query:

```graphql
query PostDetailQuery($slug: String!) {
post: postBySlug(slug: $slug) { # returns PublishedPost
...PostLayout_post
title
id
}
}

fragment PostLayout_post on Post {
title
}
```

GraphQL rejects this query because the title selection can return two different types: optional string and string. In general this makes sense as a rule, but it feels like it should be relaxed in the case of interface construction as per my example.

The parent query selects `postBySlug` which will either return null or a `PublishedPost`. So a title field at this level is _guaranteed_ to not be null. The included fragment is on type `Post` and has a title selection which would normally be nullable but because it's included within a PublishedPost is also logically guaranteed to be not null. GraphQL is rejecting the query on the basis that title could have two different return types, but it's actually impossible in this case.

Is this an oversight or a deliberate part of GraphQL's design? If it's an oversight, how challenging would it be to correct it?

(Interestingly, for those using it, Relay allowed me to construct this query without any complaints, it only failed at runtime.)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.