graphql-voyager
graphql-voyager copied to clipboard
[Feature] Implment possiblity to hide interface fields on implementations
Problem this PR tries to solve: When you have interface with lot of common fields and multiple implementation of that interface currently all fields are shown for every implementation. That unnecessary make graph bigger than it needs to be. See this issue opened for this https://github.com/APIs-guru/graphql-voyager/issues/41
Solution: I introduced new boolean in settings panel for hiding fields on objects that are from interface. Default settings is false to be compatible with current behavior. To be still able to tell what fields are available on object i added into graph information about what interfaces are implemented by object(currently it is available in side panel but not it graph itself)
Technical details: Adding new settings is quite forward.
Then in src/introspection/introspection.ts
i added function markInterfaceFields
that traverse graph and delete fields from objects that are also present in interfaces.
Additionally in src/graph/dot.ts
i added interfacesTypes
function that is responsible for rendering (adding graphdot syntax string) list of interfaces that objects implement.
Last important part is in file src/graph/type-graph.ts
which is responsible to decide what part of graph should be rendered from root type selected. Currently it search only forward from selected root. That present problem that when objects implement interface that is not reachable from root it is not shown in graph. This is kind of general problem but is really highlighted with this change because when you hide common field you will miss important part of graph(reachable fields are not shown anywhere). There are 2 solution for this problem:
- allow back propagation from discovered nodes to interfaces and than normal forward propagation from discovered interfaces
- allow back propagation from discovered nodes to interfaces but not do normal forward propagation from back visited interfaces only forward propagation to fields
Both solution ensure that all important details are shown in graph. I and my 2 coleages are more keen to first one. It is simpler to implement. It shows all information to navigate inside graph and small disadvantage that maybe it will show some nodes that you didn't ask for.
Small remark to authors code base was amazing to work with and i really enjoyed adding this feature.
Picture for TLDR
@matystl Thanks for PR and detailed explanation 👍
I need to think more about it since it introduces bidirectional relationship between interfaces and types that implement them but we can't render it in the dot.
Another problem is that it provides a very good UX if you came from the interface to type but what if you travel to type directly:
type Query {
getFoo: Foo
getBar: Bar
}
interface Foo {
foo: String
}
type Bar implements Foo {
foo: String
}
So if you tracing getFoo
UX is excellent but I'm not sure it's the same if you tracing getBar
.
In general, I need to think about it. I would travel a lot the next week but will try to give some feedback on this one. Feel free to ping me if I don't reply for too long.
I can't comment to previous comment but here is my brain dump for selection algoritm and pros and cons which different solutions might bring. It is however much bigger topic that probably need to be tacked by this PR ;-)
And to comment about traversal yes current solution is not best. When you navigate directly to type you will not see interfaces that type have or you as we had in our schema interface that is not returned from query you can't find out about it nor from docs in left nor in graph itself (unless you navigate directly to that interface type). So maybe when traversing it might be good idea to show interfaces of types (even when we will not expand that interfaces further).
Similar point can be risen for unions currently there if you navigate to type you have no chance to find out what unions is this type part of.(which is in my opinion smaller problem than interfaces).
If not shown in graph itself it would be cool if left side of docs would be fully navigable as it is currently in graphiql. (current behavior shows only interfaces that are show in graph).
Another long term solution would be to be able dynamicaly add items to graph. by that i mean on left side with docs there is everything. When we render type, parrent interfaces are only shown as list in type but when you click on it it will add it and redraw schema. From there we can show interface with all implementations either fully traversed to leafs or same logic with only list of them in graph and possibility to dynamicaly expanding it.
Dynamic/different selection part of graph might help with showing only part of graph instead of only one current root (something like give me set of types you want to plot in graph instead only one root).
Also it can help with huge schemas. I played with onegraph schema which is like 1.4MB in size and normaly voyager just freeze. When i limit number of shown nodes it was working with no problems. Therefore it might help for large schemas to limit number of defaultly shown nodes and being able to add(navigate) them dynamicaly.
Another cool example why it might be nice to have different selection algorithm is showing schema for particular query. Given query extract types and plot them in voyager with some aditional informations.
Another uscase in my mind is types that have like 50 fields which imediatly break nice flow of graph so instead of hide leaf fields there could be something like defaulty we show only 20 fields and link with ...
that would exand that to whole view.
@IvanGoncharov Did you have any time to think about what to do with this? :-)
Did you have any time to think about what to do with this? :-)
@matystl Sorry, no. I'm working on long overdue graphql-js
v15 release but I will try to find some time afterward.
+1 for wanting a feature like this, although in my case I'd like to hide the fields on the interface rather than the implementing types.