(I plan to implement it in the coming days if there's no strong objection/concern, this issue is mainly for discussion purpose)
Sangria has implemented a query complexity analysis, which is described here: http://sangria-graphql.org/learn/#query-complexity-analysis. We would like to implement something similar with Graphene.
We were able to implement a simple version (every node counts as 1) without modifying graphene code. But in order to implement a more complex and realistic version, some works need to be done inside Graphene.
The main problem we are facing is that we cannot figure out a way to add a custom property to nodes defined in our schema, something like:
class Query(graphene.ObjectType):
my_field = graphene.Field(
MyType,
description='some description',
resolver=my_func,
complexity=2,
)
Even if we can overload graphene.Field to accept the complexity parameter in the constructor, we don't really get Query or graphene.Field back in the schema. Instead, we get GraphQLField or GrapheneObjectType, which already filtered that out.
There are a few different ways to make it possible:
Allow users to add custom properties to schema definitions (kind of like how we do args in graphene.Field), which will be kept in the schema. So the user could call graphql.parse, and then calculate the complexity with parsed AST and complexity info from the schema.
Add a complexity property to graphene.Field, which is default to 1 and could be either a number or a callable with parameter args that returns a number. Then, when we parse the query in graphql-core, pass in a max_complexity or something similar, calculate the complexity of the query, and reject the query if calculated complexity exceeds it.
Please do let me know if you have any concerns or suggestions. Thanks!
Actually never mind. We figured out a way to go Route 1 without modifying graphene code (and Route 2 will change a lot of APIs, which will be very risky).
The basic idea is, you can use a private field in the type (we use _complexity), something like:
class MyType(graphene.ObjectType):
field1 = ...
field2 = ...
...
_complexity = {
'field1': 2,
}
Then, in the complexity analysis code, you can get that map back from the schema by something like schema.get_query_type().fields['fieldName'].graphene_type._complexity.
Thanks @fishy do you have any example for this? Maybe it could be nice to write some docs/tips for it.
@fishy Any chance you could share your complexity analysis code?
@fishy Would you mind sharing your implementation??
Most helpful comment
Thanks @fishy do you have any example for this? Maybe it could be nice to write some docs/tips for it.