Khan / Khan/genqlient

Using an Interface inline fragment inside of a Union is awkward to unpack

Open
#336 3 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Go
Stars
1.3k
Forks
143
Avg merge
4h 50m
Merged PRs (30d)
1

Description

When using an interface to select common fields from multiple types in a Union query, I expected genqlient to define an interface type that I could use to access my fields. Instead, it generated interface types for each type in the union and gave me no easy method to access my common interface fields.

Example Schema:
```graphql
type Query {
foo(): FooUnion
}

Union FooUnion: A | B | C

type A implements ColorInterface { ... }
type B implements ColorInterface { ... }
type C implements ColorInterface { ... }

interface ColorInterface {
color: String
relatedFoo: FooUnion
}
```

Example Query:
```graphql
query query() {
foo() {
... on ColorInterface {
color
}
}
}
```

In this case, if I want to write code to pull the color value out, I need to type assert across A, B, and C (or write a Getter interface and insert a runtime check). This is a bit of a pain, but understandable

Unfortunately, the problem compounds itself when my FooUnion items contain links to other FooUnion items that I'd like to get the color for:

```graphql
query query() {
foo() {
... on ColorInterface {
color
relatedFoo {
... on ColorInterface {
color
}
}
}
}
}
```

This creates a pretty awkward unpacking situation where I need to have a decent bit of nested boilerplate to access the fields in my query.

**Describe the solution you'd like**
It would be great if golang interface types were generated when performing an interface inline fragment on a union type.

In this case, it seems like a new interface type would need to be generated and applied to the `QueryFooA`, `QueryFooB`, and `QueryFooC` types that were generated for the Union. I poked around in the `generate/convert.go` code, but I didn't find an obvious place where a change to support this would be made.

This seems tricky to do, as the logic would need to know information about the interface inline fragment when generating the types for the union definition.

I'd consider working on this and opening a PR, but I'd like to hear from a maintainer to see how hard you think this would be (especially for someone who's never worked in the repo).

** Alternatives **

I don't have control over the schema, so changing the foo query to not return a union is not possible.

Using the `shurcooL/graphql` library made this query trivial, as it was able to unmarshal the json directly into my query object. I'd prefer to have genqlient's type protections and schema validation on my query, but this particular usecase requires so much boilerplate as to not make it worth it.

Contributor guide

Open the contributing guide

Research direction

Start by reading generate/convert.go and tracing how inline fragments on union members become QueryFooA, QueryFooB, and QueryFooC types. Use the nested ColorInterface examples in the issue to define the expected generated Go interfaces and verify that common fields can be accessed without repeated type assertions.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, graphql
Domain
api, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.