0

Im currently trying to call a field on graphql-query from code, without using the http layer. In a test case I had success using this snippet inside of a field resolver. The breakpoint hits.

var newContext = new ResolveFieldContext(context); var query = context.ParentType; var ticketQueryField = query.GetField("getTickets"); await (Task) ticketQueryField.Resolver.Resolve(context); 

So I think its possible to fill the copied ResolveFieldContext with my real needed fields/arguments and call it like this. But its very ... complicated to fill the ResolveFieldContext by hand. So maybe there is a easier way to create the context. Like:

var newContext = new ResolveFieldContext("query test { getTickets(id: 1) { number, title } }"); 

That would be really awesome and in my real scenario there a more then just field which I want to access with the generated query.

Why I want to use the Graph like this? The Batch-Loader which we are using inside the GraphQL-Types are perfect for our needs.

1 Answer 1

1

You can execute a GraphQL query without http by using the DocumentExecutor directly, and providing your own DocumentWriter if you want the data in a specific format. There is an extension method which returns JSON, but you can write your own.

https://github.com/graphql-dotnet/graphql-dotnet/blob/master/src/GraphQL.NewtonsoftJson/DocumentWriter.cs

This is an example test base class for testing queries: https://github.com/graphql-dotnet/graphql-dotnet/blob/master/src/GraphQL.Tests/BasicQueryTestBase.cs

This is a console example that returns JSON, not using http.

using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using GraphQL; using GraphQL.Authorization; using GraphQL.SystemTextJson; using GraphQL.Types; using GraphQL.Validation; using Microsoft.Extensions.DependencyInjection; namespace BasicSample { internal class Program { [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "main")] private static async Task Main() { using var serviceProvider = new ServiceCollection() .AddSingleton<IAuthorizationEvaluator, AuthorizationEvaluator>() .AddTransient<IValidationRule, AuthorizationValidationRule>() .AddTransient(s => { var authSettings = new AuthorizationSettings(); authSettings.AddPolicy("AdminPolicy", p => p.RequireClaim("role", "Admin")); return authSettings; }) .BuildServiceProvider(); string definitions = @" type User { id: ID name: String } type Query { viewer: User users: [User] } "; var schema = Schema.For(definitions, builder => builder.Types.Include<Query>()); // remove claims to see the failure var authorizedUser = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim("role", "Admin") })); string json = await schema.ExecuteAsync(_ => { _.Query = "{ viewer { id name } }"; _.ValidationRules = serviceProvider .GetServices<IValidationRule>() .Concat(DocumentValidator.CoreRules); _.RequestServices = serviceProvider; _.UserContext = new GraphQLUserContext { User = authorizedUser }; }); Console.WriteLine(json); } } /// <summary> /// Custom context class that implements <see cref="IProvideClaimsPrincipal"/>. /// </summary> public class GraphQLUserContext : Dictionary<string, object>, IProvideClaimsPrincipal { /// <inheritdoc /> public ClaimsPrincipal User { get; set; } } /// <summary> /// CLR type to map to the 'Query' graph type. /// </summary> public class Query { /// <summary> /// Resolver for 'Query.viewer' field. /// </summary> [GraphQLAuthorize("AdminPolicy")] public User Viewer() => new User { Id = Guid.NewGuid().ToString(), Name = "Quinn" }; /// <summary> /// Resolver for 'Query.users' field. /// </summary> public List<User> Users() => new List<User> { new User { Id = Guid.NewGuid().ToString(), Name = "Quinn" } }; } /// <summary> /// CLR type to map to the 'User' graph type. /// </summary> public class User { /// <summary> /// Resolver for 'User.id' field. Just a simple property. /// </summary> public string Id { get; set; } /// <summary> /// Resolver for 'User.name' field. Just a simple property. /// </summary> public string Name { get; set; } } } 
Sign up to request clarification or add additional context in comments.

1 Comment

This works just perfect! Thank you very very much! When I use the ExecutionResult I also get the strong typed objects which I can use in my UnionType. 10/10!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.