🤔 Why GraphQL needs to support the union of scalars

— 3 minute read

In my latest article on LogRocket, Creating an @export GraphQL directive, I showed the screenshot of a GraphiQL client with red lines over the query argument definitions, which indicate there is an issue going on:

GraphiQL client with issues
GraphiQL client with issues

Why is this happening? For the demonstration for my article, I have needed to print the value of the dynamic variable in the response, as to visualize that it works well. For that, I created a field echoVar, which simply echoes back the value contained in the variable.

Since the type of the values may not be known in advance (it could be a String, Int, any custom scalar, an object, or anything else), the type of echoVar is a generic Mixed type, to which all types can be "identified" with.

The consequence of using Mixed is that there will be a mismatch when loading the query in the GraphiQL client, showing a red line in the argument definitions and an error when hovering over them:

Type mismatch error shown by GraphiQL

I am not so troubled with this issue, because field echoVar is not actually needed: it was just used to see that @export behaves as expected. However, it is still annoying to see those red lines.

The solution currently supported by GraphQL is extremely verbose and unmaintainable: to create different echoVar functions for each type (echoStringVar, echoIntVar, etc). This issue should be solved in an elegant way, avoiding the verbosity from having to declare a different field per type of response.

The GraphQL spec issue linked to in my article mentions that we could provide @export with an additional argument type, but this is potentially useful only for deducing the type of the object in the GraphQL server. The hack, though, deals with the type of the object in the query, on the client.

So, how to solve this issue? There are 3 possible approaches to it. All 3 are currently unsupported by GraphQL, but this situation could change in the foreseeable future.

1. Make all scalar types implement a Serializable interface permalink

The trait in common among all scalar types (Int, Float, Boolean, String and ID, and all custom scalar types) is that they are serializable. Hence, if they implemented a Serializable interface, we could have field echoVar return this interface, and it would be satisfied not matter which actual type it returns.

However, this doesn't work, because the spec says that an interface must include at least one field, but scalar types cannot resolve fields (that's only doable by the Object type). Then, unless the spec is modified, scalar types cannot implement interfaces.

2. Support the Any scalar type permalink

The Mixed type I have use to represent any scalar type could be a type all by itself, a kind of wildcard type that says: I represent anything.

This use case is already being dealt with, through this pull request, proposing to add the Any type. However, this pull request is 3 years-old, and doesn't seem to have much activity, so I don't hold my breath about it.

3. Allow fields to return unions of scalar types permalink

Even though currently only object types can be part of union types, there is a proposal to also support the union of scalar types.

With this solution, field echoVar could be declared to return Int | Float | Boolean | String | ID, and so all of these cases would be covered.

This is the solution that seems most promising of all 3. The issue has had recent activity, is directly related to the GraphQL Input Union proposal, which is currently being worked upon by the GraphQL Working Group, and there is a champion working on it.