question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Directive on query element is not resolving arguments

See original GitHub issue

Is there an existing issue for this?

  • I have searched the existing issues

Product

Hot Chocolate

Describe the bug

I created a directive @urlContext(url: String!) for the Query element. Added a middleware and was set that for the .Use on the directive definition. When the middleware is executed the directive is found below the context.Directive but when executing context.Directive.GetArgument<string>("url") I always getting null out.

If instead adding the directive on the field/field definition the middleware and get arguments methods are working as expected.

Workaround that I found is to use this to find the directive argument value

var directive = context.Operation.Definition.Directives.FirstOrDefault(x => x.Name.Value == context.Directive.Name);
var argument = directive?.Arguments.FirstOrDefault(x => x.Name.Value == "url");
var urlString = argument?.Value.Value as string;

if ((argument?.Value.Kind != HotChocolate.Language.SyntaxKind.Variable
    || context.Variables.TryGetVariable(urlString, out urlString))
    && !string.IsNullOrEmpty(urlString)
    && Uri.TryCreate(urlString, UriKind.RelativeOrAbsolute, out var url))
{

}

Steps to reproduce

Schema

directive @UrlContext(
  """
  The url for the contextual information.
  """
  url: String = "not-set"
) on QUERY | MUTATION | FIELD | OBJECT | FIELD_DEFINITION

type Query {
  content: String!
}

Query

query @UrlContext(url: "https://github.com")  {
  content
}

Directive definition

public class UrlContext
{
    public string Url { get; set; }
}

public class UrlContextType : DirectiveType<UrlContext>
{
    protected override void Configure(IDirectiveTypeDescriptor<UrlContext> descriptor)
    {
        descriptor.Argument(x => x.Url)
            //.Type<NonNullType<StringType>>()
            .Description("The url for the contextual information.")
            .DefaultValue("not-set");

        descriptor.Location(DirectiveLocation.Query | DirectiveLocation.Mutation | DirectiveLocation.Field | DirectiveLocation.FieldDefinition | DirectiveLocation.Object);

        descriptor.Use<UrlContextMiddleware>();
    }
}

Directive middleware

public class UrlContextMiddleware
{
    private readonly FieldDelegate _next;

    public UrlContextMiddleware(
        FieldDelegate next)
    {
        _next = next;
    }

    // this method must be called InvokeAsync or Invoke
    public async ValueTask InvokeAsync(IDirectiveContext context)
    {
        // Code up here is executed before the following middleware
        // and the actual field resolver
        var url = context.Directive.GetArgument<string>("url"); // this always return null when directive is on query

        // This invokes the next middleware
        // or if we are at the last middleware the field resolver
        await _next(context);

        // Code down here is executed after all later middleware
        // and the actual field resolver has finished executing
    }
}

Relevant log output

No response

Additional Context?

No response

Version

13.0.0-preview.85

Issue Analytics

  • State:closed
  • Created 8 months ago
  • Comments:12 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
michaelstaibcommented, Feb 3, 2023

I would use headers for thinks that belong into headers. What I would be carefull with is allowing people to put contextual information on selections. The GraphQL query would become very crowded. Also, its not very clear where you have to set them.

If you set them just on the operation level it would be fine.

0reactions
Tastefulcommented, Feb 3, 2023

I have fixed the link … if you want to try again.

Thanks, now it was working.

I know that we can pass the information as http-headers and I want to avoid that as-well because looking to use GQL Federation for extensibility and I think it will be harder (if at all possible) to get that information down to the sub-graphs if needed.

Header propagation is an well-known concept with federated graphs.

Do you, from the above information, think that it’s better to send this contextual information as http-header information?

So you can access the directives on each field … we do not coerce them by default because it has a performance impact. You could do that in the query compilation phase but there are variables that could be passed into the arguments … these would prevent you from doing it there.

the query compilation phase is that the same as implementing an IHttpRequestInterceptor or how do I inject my own code inside that?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Field arguments vs. directives in GraphQL
Directives can be more efficient than field arguments​​ On execution time, a field argument will be accessed when resolving the field, which ...
Read more >
Directives - Apollo GraphQL Docs
Directives can take arguments of their own ( reason in this case). ... If true , the decorated field or fragment in an...
Read more >
Creating schema directives - Apollo GraphQL Docs
The directive takes one optional argument ( reason ) with a default value ( "No longer supported" ). The directive can decorate any...
Read more >
Unit testing Directive with arguments in Angular 2+
The directive is working fine in other components. it accepts a color argument variable defined in the ts file and use it as...
Read more >
Argument directive [QUESTION] · Issue #188 · graphql-java ...
I'm new to spring boot and graphql, and I'm trying to write a directive that checks that the argument is within a certain...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found