Open johnkm516 opened 1 year ago
Part of the problem here is how extends
interacts with intersection composition on a federated schema. If two services take a common input base type and extend them, the extension happens before composition. This is very obvious with something like a shared schema for sorting or filtering
Shared input base type:
input FieldSpecificationInput {
common: CommonFieldSpec
}
Subgraph A extended type:
extend input FieldSpecificationInput {
graphA: GraphAFieldSpec
}
Subgraph B extended type:
extend input FieldSpecificationInput {
graphB: GraphBFieldSpec
}
If you only put Graph A in your federation, the resulting composed type is:
input FieldSpecificationInput {
common: CommonFieldSpec
graphA: GraphAFieldSpec
}
But the second you add Graph B to your federation, the resulting composed type is:
input FieldSpecificationInput {
common: CommonFieldSpec
}
The extension is effectively cancelled out by intersecting composition. There doesn't seem to be any current means of changing this behavior and the two strategies of extension and composition are in direct contradiction to each other. Not only that, but intersection as a "smart" pattern just means you're quietly removing API endpoints without any errors or warnings during composition. Intersection composition means that one subgraph can cause another subgraph's contributions to be removed. I'm not sure how that's a desirable pattern for anyone or could be considered "smart".
I am trying to adopt Federation 2 but ran into what I think is a huge problem; merging input types and enums. As it says in the docs, input types and field arguments use the intersection strategy rather than the union strategy because :
I am having trouble understanding why though? Isn't it the router's job to make sure the arguments route to the correct subgraph in the first place? The same way it does for type compositions?
Consider two subgraphs Product and Inventory as per the docs :
From these models, intuitively it makes sense to me for each of the subgraphs to declare their own corresponding inputs :
Product subgraph
Inventory subgraph
The expectation would be that the input type is merged using the union strategy; the supergraph SDL keeping track of which input fields belong to which subgraph, and the gateway splitting the input argument fields that belong to each subgraph before routing the input data, therefore ensuring the router never passes an argument to a subgraph that doesn't define that argument.
By doing a intersecting merge for input types and enums I feel like there is a huge disconnect between how types are declared and composed vs how input / enums are declared and composed. Input types especially almost directly correspond to the object type, it doesn't really make sense to me why Input types are merged using the intersection strategy. This works when you're building resolvers for querying with keyFields, but for much more complicated queries dealing with collections where the input arguments could aggregate, filter, and sort, coding and querying the arguments get really complicated. It also forces me to declare multiple different input type names like this :
Inventory subgraph
and query them two separate times. For example, if I wanted to create a product with a specific name and also add the inStock field, I would have to query ProductCreateInput_Product then query ProductCreateInput_Inventory. This is just a basic example but I could extend input types to far more complicated arguments like :
Product subgraph
Inventory subgraph
in which case it gets more and more difficult to deal with input types. Do I just have a fundamental misunderstanding of how to implement subgraphs? Are there limitations that has made input types / enum compositions using the union strategy unviable?