Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Minimal API Support (v2.0) #143

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

Merged
merged 68 commits into from
Nov 26, 2023
Merged

Minimal API Support (v2.0) #143

merged 68 commits into from
Nov 26, 2023

Conversation

kevin-carroll
Copy link
Member

Minimal Api Support

Added support for "minimal api" style fields for query, mutation and subscription operations.

Highlights:

  • Full parity of configuration and features with controller based action methods
  • DI injected services
  • Access to FieldResolutionContext, DirectiveResolutionContext, and HttpContext for advanced metadata such as the active user, the current field being resolved etc.
  • Ability to return and use action results from minimal api resolvers
  • Ability to make "query groups" to group together authorization and field templating when defining field resolvers.
// Program.cs

// Example minimal API registration
var schemaBuilder = builder.Services.AddGraphQL();
schemaBuilder.MapQuery('/users/account')
             .AddResolver(async (string id, IPersonService service) => {
                    return await service.RetrievePerson(id);
             });

schemaBuilder.MapMutation('/users/newUser')
             .RequireAuthorization(Policy = "adminPolicy")
             .AddResolver(async (string userName, IPersonService service) => {
                    return await service.CreateNewUser(userName);
             });
# Sample Query
query {
    users { 
        account(id: 'abc123') {
            id
            name
        }
    }
}

Major Updates

  • Added support for "field level" dependency injection and the [FromServices] attribute. You can now inject services directly into a controller or minimal api method.
  • Completly seperated "internal" fields such as SourceArgument from the schema. ISchema is now a "pure" representation of the runtime graphql schema.
    • Internal metadata related to resolvers and method parameters can be found on the IGraphField.Resolver property.
  • Scalars are now schema based. Each schema in a multi-schema configuration can have different implementations of the same named scalar.
    • The 5 specification declared scalars (Int, Float, Bool, String, ID) remain constant and cannot be redeclared with different implementations.

Minor Updates

  • Structs can now be part of union types
  • Added a new graph attribute, [Union] to enhance the readability of defining a union on a field.

Breaking Changes

Minor Breaking Changes

These changes may effect you if you've done signifcant customization of the templating and schema generation process.

  • A complete overhaul of the templating engine was made to support anonymous and static resolver methods. See detailed changes below if you have modified or extended the templating engine.
  • Reworked and enriched FieldResolutionContext and DirectiveResolutionContext to remove dependencies on middleware contexts, constructor arguments have changed as a result.
  • Eliminated the global GraphQLProviders service locator class. All functionality has been ecapsulated to a "per schema" service injection IGraphQLSchemaFactory<TSchema>.
  • Added a new method, IScalarGraphType.Clone(), used by the runtime to create "per schema" instances of a scalar class with alternative or different type naming.
  • Merged ISchemaExtension into IGraphQLServerExtension. A custom extension need only declare the methods it wishes to implement to subscribe to those registration and setup calls.
    • Renamed SchemaOptions.AddConfigurationExtension to .AddSchemaExtension to better clarify intent
  • Added a required templating method IGraphTypeTemplateProvider.ParseType(IGraphQLRuntimeSchemaItemDefinition) to support the templatizing of minimal api fields.
  • Removed IScalarGraphType.OtherTypes. Each scalar is now locked 1:1 with a a single .NET type. All inferences or requirements of Nullable<T> are handled automatically by the runtime.

Quality of Life Improvements

  • Added support for FieldResolutionContext, DirectiveResolutionContext and HttpContext as injectable parameters to all field resolvers.
  • Added a new, overridable engine component named IGraphSchemaFactory<TSchema> used to build out a schema instance at start up. The default implementation can be swapped out per schema to better facilitate custom implementations.

Bug Fixes

  • Fixed a bug where [GraphSkip] would not be honored for some method parameter types. An exception will now be thrown if an argument to a field is declared with a type that has the Graph Skip attribute applied.
  • Fixed a bug where the InternalName of GraphArgument was being incorrectly set to the full internal name of the parameter on which the argument is based.
  • Fixed a bug where ActionMethodModelStateValidatedLogEntry was printing the return type of an action method instead of the name of the controller that owns it for the controller name property.
  • Fixed a bug with overloads of [Query], [Mutation]`` and [Subscription]` that would cause null argument exceptions in some union definitions use cases.
  • Fixed a bug with RouteNotFoundActionResult not propagating a captured exception in some scenarios. Any captured exception will now be correctly nested as an inner exception or as a top level exception depending on the route failure type.
  • Fixed a bug where fields declared or attached directly to the top level operations were not included in some built in some filtering extension methods (e.g. .AllSchemaItems())

Namespace Reorganizations

  • Moved Internal.Templates to Schema.Generation.TypeTemplates
  • Moved Internal.Resolvers to Execution.Resolvers
  • Moved Execution.TypeMakers to Schema.Generation.TypeMakers

TestServer Changes

  • Deprecated CreateGraphTypeFieldContextBuilder() and CreateActionMethodFieldContextBuilder(). Added appropriate overloads of CreateFieldContextBuilder() to simplify the interface.
  • Removed CreateFieldExecutionContext() it now exists as part of FieldContextBuilder
  • BREAKING: Exposed the Mock<T> powering FieldContextBuilder.FieldRequest instance to allow consumers to update or change the mocked values for various testing scenarios. Users of this object may need to apply FieldRequest.Object at locations where they have used .FieldRequest in the past.

Detailed ChangeLog

  • Eliminated the interface IGraphMethod, used by the base GraphController and formalized a new ISchemaItemResolverMetaData interface to encapsulate all resolver related data for any field or directive in the system.
  • Rebuilt the internal ExecutionArgumentCollection object to work off the resolution contexts (FieldResolutionContext, DirectiveResolutionContext) instead of their middleware counterparts.
  • Moved batch completion to its own action result. Completion of batched type extension (e.g. the generation of the resultant dictionary) is no longer done as part of the builder operation during the developer's resolver method and is instead offloaded to the runtime.
  • Removed IGraphArgumentCollection.SourceArgument. Its now handled by the resolver by and not part of the schema.
  • Concrete class MethodGraphField must supply a declaredReturnType during its constructor. It will no longer try to infer a valid return type from the supplied resolver.
  • Concrete class MethodGraphField must supply a objectType during its constructor. It will no longer try to infer a valid return type from the supplied resolver.
  • Renamed and rebuilt IGraphFieldResolverMethod to IGraphFieldResolverMetaData and decoupled it from any graphql dependent objects. This object now represents ONLY data related to the invocation of a C# method or property.
  • IGraphField not correctly implements ITypedSchemaItem
  • Removed the unnecessary enum value Internal on the GraphArgumentModifiers enumeration. Use Enum.IsPartOftheSchema() and IsNotPartOfTheSchema() instead to determine the nature of the a parameter's location.
  • Simplified the logic for the ISchemaItem.InternalName. All schema items are now referrred to by a singular internal name that defaults to the full name of the entity (e.g. MyObject.MyMethod). A new optional property has been added to all graph attributes to allow the setting of a custom InternalName to use in log entries and exception methods (e.g. [Query(InternalName = "MyCustomName")]).
    • The property ISchemaItem.InternalFullName has been eliminated
    • Decoupled all internal indexing and lookup values away from InternalName. InternalName is now only for exception and log message references.
  • Renamed IEnumValue.InternalValue to DeclaredValue to separate its intent from InternalName. This property is readonly.
  • Added IEnumValue.DeclaredLabel to separate the required, code-defined label from the developer's customizable InternalName
  • Renamed GraphFieldTemplate.PossibleTypes to PossibleObjectTypes to better clarify the intent of the contained items.
  • Removed the configuration options parameter from .AddSubscriptionPublishing(), it was not being used.
  • Eliminated the internal static container for tracking registered schemas. All checks for schema registration are limited to a given IServiceCollection. This enables support for multiple "multi-schema" IServiceProviders per service instance if the option is ever needed.
  • Changed the exception thrown when a schema is registered twice to a single IServiceCollection to be an InvalidOprationException to help with clarity (formally GraphTypeDeclarationException).
  • Removed IGraphArgument.ArgumentModifiers. ArgumentModifiers are now part of the resolver parameters and not part of the generated ISchema.
  • Eliminated the need for concrete PropertyGraphField class. All fields are (property and method based) are now implemented via MethodGraphField.
  • Scalar names now obey the formatting and naming conventions just like other types.
  • Built in templates will no longer attempt to pre-determine which dependent types are scalars or input objects. That function has been moved to the type makers, where the schema is now in focus and custom scalars can be accurately determined.
    Normalized IUnionGraphTypeMaker its no long a "special case" usage of a type maker.

Also:
* decoupled directive resolver methods from templates
* removed non-schema arguments from the schema data (only exists in resovler meta data)
@kevin-carroll kevin-carroll added the v2.0 To be completed for the v2.0 release label Nov 26, 2023
@kevin-carroll kevin-carroll merged commit 3527a53 into release/2.0 Nov 26, 2023
@kevin-carroll kevin-carroll deleted the feature/55-minimalApi branch November 26, 2023 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
v2.0 To be completed for the v2.0 release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.