Skip to content

Why does GraphQL merge fields across fragment type targets? #399

Closed
@mike-marcacci

Description

@mike-marcacci

I've recently been fighting with some of the ergonomic downsides to field selection merging – notably field conflict errors and their stifling frequency when dealing with heterogeneous lists and mutations with relay. As I've been thinking through various solutions, I've become curious as to why merging happens at all.

And so that's my question for people with a better knowledge of GraphQL's history: why do we merge fields? I'm sure this was discussed at some point, but I couldn't find it, so I'm going to make a few arguments against merging, with the suspicion that somebody will have a better argument for merging that I missed. :-)

Better Input/Output Symmetry

Input/output symmetry is one of GraphQL's features that helps make it so immediately intuitive. To me, the following query:

query {
	something {
		id

		...on Dog {
			breed
		}

		...on Car {
			make
		}
	}
}

could just as intuitively return:

{
	"something": {
		"id": "9121c30a-941a-4a05-b6ae-c202b6d62522",

		"__on<Dog>": {
			"breed": "Huskey"
		},

		"__on<Car>": {
			"make": "Toyota"
		}
	}
}

as its merged counterpart.

Eliminates Most Field Conflicts

This also greatly reduces the liklihood of field conflicts, meaning queries like the one below can actually be run:

query {
	someGeoQuery {
		id

		...on POI {
			__typename
			coordinates #GeoJSONPointCoordinates
		}

		...on City {
			__typename
			coordinates #GeoJSONPolygonCoordinates
		}
	}
}

Better Interop With Clients & Tools Like Relay

My biggest frustration with the current implementation is not being able to actually reuse fragments when I expect a heterogeneous response. For example, I have an offline-first app where changes are staged in a changeset; this changeset can then be committed when the user is online. Because of precautionary field merge conflicts (not real conflicts, but ones that may exist in the future if I changed a concrete type to be an interface) it's exceedingly difficult to reuse fragments for the mutation response. There are plenty of ways around this, but I'm not sure this is the kind of thing that should need to be worked around.

Simpler Server Implementation

The simplest way to do something is almost always to not do it :-)


Hopefully I've made some interesting points here, and I'm very curious to hear some thoughts in the opposite direction!

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