1

using the documented RequiresAuthValidationRule implementation;

https://github.com/graphql-dotnet/graphql-dotnet/blob/master/docs/learn.md

There is an example of checking if a field has certain permission and if a user can access that field.

_.Match(fieldAst =>{...})

It looks like the GraphQL engine is walking a tree and calling the IValidationRule.Validate(...) at each node.

What is the best way to know what the full path of the field is.

The starwars example;
https://github.com/graphql-dotnet/graphql-dotnet/blob/master/docs/getting-started.md

i.e. i want to know that the field is human->friends->name when I am at the 'name' node.

From what I can see I only have visibility to the current field node and it children, but not its parents.

Herb Stahl
  • 439
  • 1
  • 6
  • 23

2 Answers2

0

Depending on what you need, ValidationContext.TypeInfo.GetLastType() and/or ValidationContext.TypeInfo.GetParentType() should be what you need. ValidationContext.TypeInfo has a lot of context for where you are in the graph.

Here's an example from ScalarLeafs validation rule:

public class ScalarLeafs : IValidationRule
{
    public INodeVisitor Validate(ValidationContext context)
    {
        return new EnterLeaveListener(_ =>
        {
            _.Match<Field>(f => Field(context.TypeInfo.GetLastType(), f, context));
        });
    }

    private void Field(IGraphType type, Field field, ValidationContext context)
    {
      ...
    }
}
Joe McBride
  • 3,789
  • 2
  • 34
  • 38
0

For efficiency, with hints from Joe McBride, I opted to create my own MyEnterLeaveListener based upon the GraphQL-dotnet EnterLeaveListener source.

public class EnterLeaveListenerState
{
   public OperationType OperationType { get; private set; }
   public string CurrentFieldPath { get; private set; }
}

public class MyEnterLeaveListener : INodeVisitor, IEventSource<IEnterLeaveListenerEventSink>  
{
    ....
    public void Enter(INode node)
    {
        var isField = TypeHelper<Field>.IsType(node.GetType());
        var isOperation = TypeHelper<Operation>.IsType(node.GetType());

        if (isOperation)
        {
            var operation = node as Operation;
            OperationType = operation.OperationType;
            RunningPath.Clear();
            FireEnterLeaveListenerState(new EnterLeaveListenerState(OperationType, CurrentFieldPath));
        }
        if (isField)
        {
            var field = node as Field;
            var next = CurrentFieldPath + "/" + field.Name;
            RunningPath.Push(next);
            FireEnterLeaveListenerState(new EnterLeaveListenerState(OperationType, CurrentFieldPath));
        }
        _listeners
            .Where(l => l.Enter != null && l.Matches(node))
            .Apply(l => l.Enter(node));
    }

    public void Leave(INode node)
    {
        var isField = TypeHelper<Field>.IsType(node.GetType());
        if (isField)
        {
            var field = node as Field;
            RunningPath.Pop();
            FireEnterLeaveListenerState(new EnterLeaveListenerState(OperationType, CurrentFieldPath));
        }
        _listeners
            .Where(l => l.Leave != null && l.Matches(node))
            .Apply(l => l.Leave(node));
    }
    ....

}

I build out the operation and path as I go and event out any change.

Herb Stahl
  • 439
  • 1
  • 6
  • 23