-
Notifications
You must be signed in to change notification settings - Fork 68
Description
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: seems very complicated compared to the spring boot graphql #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
_entities
fetchers and_Entity
type 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
@extends
directive- 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
@key
usages, and that each@key
usage may specify multiple fields (additionally with nesting). - Note that a federation reference passed to the
_entities
resolver may additionally contain extra fields as needed by@requires
. - Parsing/validating
fields
is going to be a bit trickier here, as the grammar forfields
is basically aSelectionSet
without braces with some additional limitations/validation rules, and I haven't looked into how difficult it would be forgraphql-java
to 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
resolveReference
which each type object could extend from. In most cases it would be creating a new object, setting the@external
fields with the matching@key
fields 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 @key
s, nested fields in @key
s, 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 #103 (comment)