federation-jvm
federation-jvm copied to clipboard
Provide some sensible defaults that can be activated through a simple mechanism (eg: inheritance)
Creating a separate ticket to follow through with the ideas raised as part of PR #103 around providing some automation / sensible defaults that would allow Java Graph Builders to more easily add the necessary federation queries and resolvers.
Some related material:
- netflix/dgs-framework DefaultDgsFederationResolver.kt
- rkudryashov/graphql-java federation - On the surface this looks like it was trying to provide some abstracted magic
- Related issues: #65
Below is a copy of the original comments
@setchy Thanks for the suggestions! I do think it would be nice for users to:
- Have more automation around defining
_entitiesfetchers and_Entitytype resolvers. - Have some sane defaults they can activate through some simple mechanisms (e.g. inheritance).
With regards to your specific suggestions:
- could the string references for any federated types (ie: "Product") be replaced by something powered by parsing any SDL types with the
@extendsdirective- could the string references for key fields (ie: "upc") be replaced by something powered by parsing any SDL types with the
@key(fields: "...")directive
For some clarifying context, a GraphQL type is an entity type if it has an @key directive, or if it implements an interface with an @key directive. Since we're given the GraphQLSchema in Federation#transform(), we can indeed use this to determine:
- The GraphQL type names for all entity types.
- The possible key fields for each entity type.
- Note that an entity type can have multiple
@keyusages, and that each@keyusage may specify multiple fields (additionally with nesting). - Note that a federation reference passed to the
_entitiesresolver may additionally contain extra fields as needed by@requires. - Parsing/validating
fieldsis going to be a bit trickier here, as the grammar forfieldsis basically aSelectionSetwithout braces with some additional limitations/validation rules, and I haven't looked into how difficult it would be forgraphql-javato parse this particular symbol with a separate set of validation rules.
- Note that an entity type can have multiple
For the switch statements in the _entities fetcher and the _Entity type resolver, we could automate that if we let users register wirings for each entity type, e.g. looking like
public interface EntityWiring {
// The GraphQL type name of the entity.
public String getName();
// Resolves a federation reference to an object representing the entity type.
public Object resolveReference(Map<String, Object> reference);
// Determines whether an object represents this specific entity type.
public boolean isType(Object object);
}
We could then validate that they provide wirings for every entity type present in the schema. We could probably infer some of these automatically if the user's using a library like graphql-java-annotations where we have a well-defined correspondence between Java types and GraphQL types.
Regarding the automation of parsing of the federation reference, we could eliminate at least some boilerplate and provide type safety using something similar to JSON object mapping, where the user provides POJO classes and we validate them against the parsed @key and @requires fields. Their resolveReference() function could then take in their own class instead of having to walk Map<String, Object>. (If we can leverage code-generation tools, we could additionally generate the POJO classes for the user.)
- could their be a base class that provides a default implementation of the
resolveReferencewhich each type object could extend from. In most cases it would be creating a new object, setting the@externalfields with the matching@keyfields and returning that new object. The type or field level resolvers could then add the necessary service layer call to populate the additional data (ie: "quantity", "inStock")
I'm not sure if we could do this exactly as written, as resolveReference() would be static and statics can't be overridden via inheritance. This also becomes trickier for the cases of multiple @keys, nested fields in @keys, and @requires fields. A potential solution that comes to mind is one where the user provides constructors that take in their POJO class, and we use reflection or annotations to detect those constructors to set up resolveReference() in an EntityWiring.
Circling back to this PR, while I believe it would be nice to provide automation and reduce boilerplate, I wouldn't say it's in scope for this PR. If you're interested in contributing to federation-jvm, you can file a GitHub issue referencing this thread and we can work through developing a more concrete proposal. 🙂
Originally posted by @sachindshinde in https://github.com/apollographql/federation-jvm/issues/103#issuecomment-820741515