1

I am thinking should I audit user queries in HttpRequestInterceptor or DiagnosticEventListener for Hot Chocolate v11. The problem with latter is that if the audit failed to write to disk/db, the user will "get away" with the query.

Ideally if audit fail, no operation should proceed. Therefore in theory I should use HttpRequestInterceptor.

But How do I get IRequestContext from IRequestExecutor or IQueryRequestBuilder. I tried googling but documentation is limited.

Jason
  • 13
  • 3

1 Answers1

4

Neither :)

The HttpRequestInterceptor is meant for enriching the GraphQL request with context data.

The DiagnosticEventListener, on the other hand, is meant for logging or other instrumentations.

If you want to write an audit log, you should instead go for a request middleware. A request middleware can be added like the following.

services
    .AddGraphQLServer()
    .AddQueryType<Query>()
    .UseRequest(next => async context => 
    {

    })
    .UseDefaultPipeline();

The tricky part here is to inspect the request at the right time. Instead of appending to the default pipeline, you can define your own pipeline like the following.

services
    .AddGraphQLServer()
    .AddQueryType<Query>()
    .UseInstrumentations()
    .UseExceptions()
    .UseTimeout()
    .UseDocumentCache()
    .UseDocumentParser()
    .UseDocumentValidation()
    .UseRequest(next => async context =>
    {
        // write your audit log here and invoke next if the user is allowed to execute

        if(isNotAllowed) 
        {
            // if the user is not allowed to proceed create an error result.
            context.Result = QueryResultBuilder.CreateError(
                ErrorBuilder.New()
                    .SetMessage("Something is broken")
                    .SetCode("Some Error Code")
                    .Build())
        }
        else 
        {
            await next(context);
        }
    })
    .UseOperationCache()
    .UseOperationResolver()
    .UseOperationVariableCoercion()
    .UseOperationExecution();

The pipeline is basically the default pipeline but adds your middleware right after the document validation. At this point, your GraphQL request is parsed and validated. This means that we know it is a valid GraphQL request that can be processed at this point. This also means that we can use the context.Document property that contains the parsed GraphQL request.

In order to serialize the document to a formatted string use context.Document.ToString(indented: true).

The good thing is that in the middleware, we are in an async context, meaning you can easily access a database and so on. In contrast to that, the DiagnosticEvents are sync and not meant to have a heavy workload.

The middleware can also be wrapped into a class instead of a delegate.

If you need more help, join us on slack.

Click on community support to join the slack channel: https://github.com/ChilliCream/hotchocolate/issues/new/choose

Joundill
  • 6,828
  • 12
  • 36
  • 50