Skip to main content

A python library that provides complexity calculation helpers for GraphQL

Project description

graphql-complexity

Python library to compute the complexity of a GraphQL operation

Unit Tests

Usage

The library uses the query complexity algorithm to compute the complexity of a GraphQL operation. The algorithm is based on the number of fields requested in the operation and the depth of the query.

from graphql_complexity import (get_complexity, SimpleEstimator)

query = """
    query SomeQuery {
        user {
            id
            name
        }
    }
"""

complexity = get_complexity(query, estimator=SimpleEstimator(complexity=1, multiplier=1))
if complexity > 10:
    raise Exception("Query is too complex")

Estimators

In order to get the complexity of a query, an estimator needs to be defined. The main responsibility of the estimator is to give each node an integer value representing its complexity and (optionally) a multiplier that reflects the complexity in relation to the depth of the query.

There are two built-in estimators, plus the capability to create any new estimator by implementing the ComplexityEstimator interface.

Estimate fields complexity based on constants for complexity and multiplier

This estimator assigns a constant complexity value to each field and multiplies it by another constant which is propagated along the depth of the query.

from graphql_complexity import SimpleEstimator


estimator = SimpleEstimator(complexity=2, multiplier=1)

Given the following query:

query {
    user {
        name
        email
    }
}

As the complexity and multiplier are constant, the complexity of the fields will be:

Field Complexity
user 1
name 2 * (2 * 1)
email 2 * (2 * 1)

And the total complexity will be 6.

Define fields complexity using schema directives

Assigns a complexity value to each field and multiplies it by the depth of the query. It also supports the @complexity directive to assign a custom complexity value to a field.

This approach requires to provide the schema to the estimator.

from graphql_complexity import DirectivesEstimator


schema = """
directive @complexity(
  value: Int!
) on FIELD_DEFINITION

type Query {
  oneField: String @complexity(value: 5)
  otherField: String @complexity(value: 1)
  withoutDirective: String
}
"""

estimator = DirectivesEstimator(schema)

Given the schema from above and the following query:

query {
    oneField
    otherField
    withoutDirective
}

The complexity of the fields will be:

Field Complexity Comment
oneField 5
otherField 1
withoutDirective 1 The default complexity for fields without directive is 1, this can be modified by parameters.

And the total complexity will be 7.

Create a custom estimator

This option allows to define a custom estimator to compute the complexity of a field using the ComplexityEstimator interface. For example:

from graphql_complexity import ComplexityEstimator


class CustomEstimator(ComplexityEstimator):
    def get_field_complexity(self, node, key, parent, path, ancestors) -> int:
        if node.name.value == "specificField":
            return 100
        return 1

    def get_field_multiplier(self, node, key, parent, path, ancestors) -> int:
        return 1

Supported libraries (based on GraphQL-core)

The library is compatible with the following GraphQL libraries:

Strawberry

The library is compatible with strawberry-graphql. To use the library with strawberry-graphql, you need to install the library with the strawberry-graphql extra.

poetry install --extras strawberry-graphql

To use the library with strawberry-graphql, you need to use the build_complexity_extension method to build the complexity extension and add it to the schema. This method receives an estimator and returns a complexity extension that can be added to the schema.

import strawberry
from graphql_complexity.extensions.strawberry_graphql import build_complexity_extension

@strawberry.type
class Query:
    @strawberry.field()
    def hello_world(self) -> str:
        return "Hello world!"

extension = build_complexity_extension()
schema = strawberry.Schema(query=Query, extensions=[extension])

schema.execute_sync("query { helloWorld }")

The build_complexity_extension method accepts an estimator as optional argument giving the possibility to use one of the built-in estimators or a custom estimator.

Credits

Estimators idea was heavily inspired by graphql-query-complexity.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

graphql_complexity-0.1.0.tar.gz (8.0 kB view hashes)

Uploaded Source

Built Distribution

graphql_complexity-0.1.0-py3-none-any.whl (9.9 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page