Calculate query comlexity outside validation context
BeeHiveJava opened this issue · 4 comments
I was wondering if it's possible to calculate complexity based on the current query, statically. In an ideal situation we'd be able to pass a string containing a GraphQL query or an info object which would return the complexity for that query.
This way we would be able to display the cost of a query to the user similar to how GitHub does: https://developer.github.com/v4/guides/resource-limitations/#returning-a-calls-rate-limit-status.
I've tried fiddling around by manually invoking the nodeComplexity function:
class SomeResolver {
public async resolve(root: any, args: any, ctx: IAppContext, info: GraphQLResolveInfo): Promise<number> {
const context = new ValidationContext(info.schema, ... /* I have no idea how to get this */ , new TypeInfo(info.schema));
const complexity = this.getQueryComplexity(ctx)(context) as QueryComplexity;
const result = complexity.nodeComplexity(..., ... /* I have no idea how to get these */ );
return result;
}
private getQueryComplexity(ctx: IAppContext): Function {
return queryComplexity({
maximumComplexity: 1000,
variables: ctx.request.query.variables,
estimators: [
fieldConfigEstimator(),
simpleEstimator({
defaultComplexity: 1
})
]
});
}
}
interface IAppContext {
request: express.Request;
response: express.Response;
}
But as you can see I have no idea how to manually get a DocumentNode
for the ValidationContext
and I have no idea how to get a FieldNode
and typeDef
for the nodeComplexity
function.
That being said I don't even know if this would be the right way to do this, maybe I'm missing something?
Displaying the calculated complexity is already possible via the onComplete
option. You can then use that value to return it as HTTP headers or add is as extensions:
https://github.com/graphql/express-graphql#providing-extensions
If you want to calculate the complexity independently from the query execution and validation, you could simply run the validation with only that rule. This could also be placed in resolvers etc.
Check the tests for an example:
Yes, calculating the complexity independently from the query execution is what I'm looking for. I figured out a way to do this by invoking the validation function and returning a deferred promise from the onComplete
function. Your solution using the ComplexityVisitor
seems way better.
That being said, I can't see ComplexityVisitor
being exported anywhere though? Thanks for your help so far, I think we should document this as I'm certain other people will run into this as well.
That being said, I can't see ComplexityVisitor being exported anywhere though?
That's just the default export being named that way in the test files...
I think we should document this as I'm certain other people will run into this as well.
Maybe it makes sense to build a helper function that is exported by this package. Something like this:
function calculateComplexity(options: {
estimators: ComplexityEstimator[],
schema: GraphQLSchema,
query: DocumentNode,
variables?: ObjMap<mixed>
}): number;
This could then be used in any context and would also allow to calculate the complexity of a partial query by passing any query node.
Basically just wrapping the test functionality in that interface.
I'd happily merge a PR for that
This is now added as getComplexity
in version > v0.3.0. Thanks for the contribution!