diff --git a/README.md b/README.md index 6ae2d8f..d6c55bc 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,65 @@ ## Overview -GraphQL.DI enhances GraphQL.NET's code-first approach by providing dependency injection support for field resolvers through the `DIObjectGraphBase` class. This enables a more maintainable and testable approach to building GraphQL APIs by allowing services to be injected directly into your field resolver classes. - -## Type-First vs Code-First in GraphQL.NET +GraphQL.DI enhances GraphQL.NET's code-first approach by providing dependency injection support for +field resolvers through the `DIObjectGraphBase` class. This enables a more maintainable and testable +approach to building GraphQL APIs by allowing services to be injected directly into your field resolver classes. + +## Getting Started + +1. **Install the NuGet package** + ```bash + dotnet add package Shane32.GraphQL.DI + ``` +2. **Add `.AddDI()` to your `AddGraphQL(...)` registration** + Register your schema and resolvers, for example: + ```csharp + services.AddGraphQL(b => b + .AddSystemTextJson() + .AddSchema() + .AddDI() + .AddGraphTypes() + .AddClrTypeMappings() + .AddExecutionStrategy(OperationType.Query) + ); + ``` +4. **Create your DI-based graph types** + ```csharp + public class TodoMutation : DIObjectGraphBase + { + private readonly IRepository _repository; + + public TodoMutation(IRepository repository) + { + _repository = repository; + } + + public async Task AddAsync(string title, string? notes) + { + var todo = new Todo { + Title = title, + Notes = notes, + }; + return await _repository.InsertAsync(todo, RequestAborted); + } + } + ``` +5. **Add the new graph types to your schema** + ```csharp + public class MutationType : ObjectGraphType + { + public MutationType() + { + Field>("todo") + .Resolve(_ => ""); + } + } + ``` + +See the [Setup](#setup) section below for more detailed instructions on configuring GraphQL.DI in +your project, including how to configure root types for use with GraphQL.DI. + +## Background: Type-First vs Code-First in GraphQL.NET ### Type-First Approach @@ -58,7 +114,7 @@ public class TodoType : ObjectGraphType ``` This can solve both issues noted above -- the data model is separate from the GraphQL type definition, -and services can be resolved via dependency injection in the constructor. However, graph types are +and services can be resolved via dependency injection in the constructor. However, graph types are effectively singletons (typically) within the dependency injection container, so if your services (such as `IRepository` above) is a scoped service, then your code will not run properly. @@ -76,8 +132,8 @@ public class TodoType : ObjectGraphType .Resolve(context => { var repository = context.RequestServices!.GetRequiredService(); - return repository.GetPersonById(context.Source.CompletedByPersonId)); - } + return repository.GetPersonById(context.Source.CompletedByPersonId); + }); } } ``` @@ -240,14 +296,14 @@ public static User GetUser(int id) => this.GetById(id); public static User GetById(this IResolveFieldContext context, int id) { var repository = context.RequestServices!.GetRequiredService>(); - return repository.GetById(int); + return repository.GetById(id); } ``` ## Advanced Usage Please note that unlike GraphQL.NET type-first resolvers, only public methods are resolved by default. -Properties and field are ignored, as well as private or protected members. +Properties and fields are ignored, as well as private or protected members. This more closely mimics the design of controllers within ASP.NET. ### Service Lifetime @@ -360,41 +416,41 @@ All other type-first attributes from GraphQL.NET are supported, such as `[Id]`, ## Setup -1. Install the NuGet package: - -```bash -dotnet add package Shane32.GraphQL.DI -``` - -2. Register your types with the DI container: - -```csharp -services.AddGraphQL(b => b - .AddSystemTextJson() - .AddSchema() - .AddDI() // Register and configure GraphQL.DI types defined within the assembly - .AddGraphTypes() // Register GraphQL.NET types defined within the assembly - .AddClrTypeMappings() // Enable automatic CLR type mappings - .AddExecutionStrategy(OperationType.Query) // Specify serial execution strategy -); -``` - -3. Define your schema with root DI graph types (if/as needed): - -```csharp -public class TodoSchema : Schema -{ - public TodoSchema( - IServiceProvider serviceProvider, - QueryType queryType, // sample where QueryType inherits DIObjectGraphType - DIObjectGraphType mutationType) // sample where Mutation inherits DIObjectGraphBase - : base(serviceProvider) - { - Query = queryType; - Mutation = mutationType; - } -} -``` +1. **Install the NuGet package:** + + ```bash + dotnet add package Shane32.GraphQL.DI + ``` + +2. **Register your types with the DI container:** + + ```csharp + services.AddGraphQL(b => b + .AddSystemTextJson() + .AddSchema() + .AddDI() // Register and configure GraphQL.DI types defined within the assembly + .AddGraphTypes() // Register GraphQL.NET types defined within the assembly + .AddClrTypeMappings() // Enable automatic CLR type mappings + .AddExecutionStrategy(OperationType.Query) // Specify serial execution strategy + ); + ``` + +3. **Define your schema with root DI graph types (if/as needed):** + + ```csharp + public class TodoSchema : Schema + { + public TodoSchema( + IServiceProvider serviceProvider, + QueryType queryType, // sample where QueryType inherits DIObjectGraphType + DIObjectGraphType mutationType) // sample where Mutation inherits DIObjectGraphBase + : base(serviceProvider) + { + Query = queryType; + Mutation = mutationType; + } + } + ``` ## Additional Samples