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

Schema Builder #369

Closed
michaelstaib opened this issue Nov 27, 2018 · 12 comments
Closed

Schema Builder #369

michaelstaib opened this issue Nov 27, 2018 · 12 comments
Assignees
Milestone

Comments

@michaelstaib
Copy link
Member

michaelstaib commented Nov 27, 2018

The schema builder shall provide a simpler API to create a schema. Moreover, the goal of this issue is to create feature parity between schema-first, code-first and poco driven schemas. Furthermore, we want to simplify the type initialization process and make it easier to generate dynamic types like for Prisma-style filter objects.

Last but not least the current schema declaration API shall not be broken. The goal here would be that the old schema factories use the schema builder underneath. Users can then decide which API approach they like more.

We have started with a simple interface ISchemaBuilder

public interface ISchemaBuilder
{
    ISchemaBuilder Use(FieldMiddleware middleware);

    ISchemaBuilder AddSource(string sourceText);

    ISchemaBuilder AddType(Type type);

    ISchemaBuilder AddType(INamedType type);

    ISchemaBuilder AddRootType(Type type, OperationType operation);

    ISchemaBuilder AddRootType(ObjectType type, OperationType operation);

    ISchemaBuilder AddResolver(FieldResolver resolver);

    ISchemaBuilder AddBinding(object binding);

    ISchemaBuilder AddServices(IServiceProvider services);

    ISchema Create();
}

Currently we have two open issues:

How shall bindings work? This ones are mainly for the schema first approach:
ISchemaBuilder AddBinding(object binding);

Further, we are pondering the idea of completely removing the service provider from the schema. So, with that ISchemaBuilder AddServices(IServiceProvider services); would be removed.

The thinking here is that the services that you associate with the schema are not scoped and are not used during execution so they are a bit confusing to the user. Moreover, do we really want dependency injection into our types or should dependency injection be restricted to resolvers and middleware components etc.

Extensions

In order to keep a small builder interface but provide more convenience we will add some extension methods on the builder like the following:

public static class SchemaBuilderExtensions
{
   public static ISchemaBuilder AddQueryType(
       this ISchemaBuilder builder,
       Type type)
   {
       return builder.AddRootType(type, OperationType.Query);
   }

   public static ISchemaBuilder AddQueryType(
       this ISchemaBuilder builder,
       ObjectType queryType)
   {
       return builder.AddRootType(queryType, OperationType.Query);
   }

   public static ISchemaBuilder AddQueryType<TQuery>(
       this ISchemaBuilder builder)
   {
       return builder.AddRootType(typeof(TQuery), OperationType.Query);
   }
}

Usage

ISchema schema = SchemaBuilder.New()
    .AddQueryType<Bar>()
    .AddSource("")
    .Use(next => context => next(context))
   .Create();

Type Initialization

We have to review how we can simplify the initialization API and open this up to be extended by users. Types should be immutable once the builder creates the schema. Moreover, we want to be able to use builder services that enable the user to change defaults like how we extract the names from clr types and so on.

@michaelstaib michaelstaib added this to the 0.11.0 milestone Nov 27, 2018
@michaelstaib michaelstaib changed the title SchemaBuilder Schema Builder Nov 29, 2018
@michaelstaib michaelstaib modified the milestones: 0.11.0, 0.8.0 Jan 3, 2019
@michaelstaib michaelstaib pinned this issue Jan 30, 2019
@michaelstaib michaelstaib modified the milestones: 0.8.0, 0.9.0 Jan 31, 2019
@michaelstaib
Copy link
Member Author

In order to make the type system easier to extend we also will now open up the descriptor types and the types themself. We will start, with the descriptor types and the work our way through to the type initialization etc.

This will let users create their own base classes that can provide a custom configuration behavior for things like filter types and so on.

@michaelstaib
Copy link
Member Author

Work on this issue can also be tracked here #597

@michaelstaib
Copy link
Member Author

michaelstaib commented Mar 5, 2019

Type Initialization

The type initialization will now be done in two phases.

Phase one will register external dependencies like types on which this type depends or resolvers.

Type dependencies can be registered in two variants, dependencies that require the the type on which a type is dependent to be fully completed or dependencies that just require the instance of a type to be created.

In both case the dependency context will return a ResolveType<T> where T is ITypeSystemObject

delegate T ResolveType<T>(ICompletionContext context) where T : ITypeSystemObject

When the type is being completed these type resolvers can be executed.

@michaelstaib
Copy link
Member Author

With the above type initialization we would introduce some potential issues:

  • extensions
    If extensions depend in the type names then we might not be able to determine to which type an
    extension belongs to until the type is completed

  • schema first
    Schema first depends on name references an could be problematic

@michaelstaib
Copy link
Member Author

michaelstaib commented Mar 5, 2019

Maybe we could introduce something like a type name resolver. Though, this would introduce an additional initialization step....

  1. Register Dependencies
  2. Complete Name
  3. Complete Type

The name is such an issue since we want to fully support generic types. Generic types a currently possible, but not in a nice way.

For instance the connection type should be able to ask for the name of the edge type etc. and build with this name its own name.

@michaelstaib
Copy link
Member Author

michaelstaib commented Mar 8, 2019

TODOs:

  • Resolve ClrType through completion context (Schema First BindType)
  • Extend helper on the descriptors

@michaelstaib
Copy link
Member Author

michaelstaib commented Mar 22, 2019

  • Binding Compiler

@radubuciuceanu
Copy link

radubuciuceanu commented Mar 23, 2019

Currently, the schema-first approach does not support single line and mutliline documentation (see GraphQL Specifications from June 2018).

The following one will not work when we try to use the schema-first approach:

"""
A simple GraphQL schema which is well described.
"""
type Query {
  """
  Translates a string from a given language into a different language.
  """
  translate(
    "The original language that `text` is provided in."
    fromLanguage: Language

    "The translated language to be returned."
    toLanguage: Language

    "The text to be translated."
    text: String
  ): String
}

"""
The set of languages supported by `translate`.
"""
enum Language {
  "English"
  EN

  "French"
  FR

  "Chinese"
  CH
}

I made a little research and I didn't manage to find any .net GraphQL implementation that supports this. Is this one related to this issue? Thx you 🙄

@michaelstaib
Copy link
Member Author

This should work, at least our parser will parse that correctly. I will write a little test tonight. If it is the bug we will fix it with the upcoming patch release next week.

@michaelstaib
Copy link
Member Author

@radubuciuceanu

I have opened another issue and will add comments there.

#647

This was referenced Mar 28, 2019
@michaelstaib
Copy link
Member Author

Add support for multi-dimensional lists with this one #676

@michaelstaib
Copy link
Member Author

The main work on this one is now finished and I close this issue ... we will add further issues to deal with certain aspects.

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

3 participants