Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide some sensible defaults that can be activated through a simple mechanism (eg: inheritance) #108

Open
setchy opened this issue Apr 21, 2021 · 0 comments

Comments

@setchy
Copy link
Contributor

setchy commented Apr 21, 2021

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:

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 for fields is basically a SelectionSet without braces with some additional limitations/validation rules, and I haven't looked into how difficult it would be for graphql-java to parse this particular symbol with a separate set of validation rules.

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 @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 #103 (comment)

@setchy setchy changed the title Create sane defaults that can be activated through some simple mechanism (eg: inheritance) automation for defining _entities fetchers and _Entity type resolvers@setchy Thanks for the suggestions! I do think it would be nice for users to: Automate some sane defaults that can be activated through a simple mechanism (eg: inheritance) Apr 21, 2021
@setchy setchy changed the title Automate some sane defaults that can be activated through a simple mechanism (eg: inheritance) Provide some sensible defaults that can be activated through a simple mechanism (eg: inheritance) Apr 21, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant