Giter VIP home page Giter VIP logo

graphql-complexity's Introduction

GraphQL Complexity

Welcome to GraphQL-Complexity! This Python library provides functionality to compute the complexity of a GraphQL operation, contributing to better understanding and optimization of your GraphQL APIs. This library is designed to be stable, robust, and highly useful for developers working with GraphQL.

Build PyPI codecov

Features

  • Compute complexity of GraphQL queries
  • Multiple built-in estimators for complexity computation
  • Customizable estimators for specific use cases
  • Support for Strawberry GraphQL library

Installation (Quick Start)

You can install the library via pip:

pip install graphql-complexity

For Strawberry GraphQL integration, use the following command:

pip install graphql-complexity[strawberry-graphql]

Getting Started

Create a file named complexity.py with the following content:

from graphql_complexity import get_complexity, SimpleEstimator
from graphql import build_schema


schema = build_schema("""
    type User {
        id: ID!
        name: String!
    }
    type Query {
        user: User
    }
""")

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

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

The library exposes the method get_complexity with the algorithm to compute the complexity of a GraphQL operation. The algorithm visits each node of the query and computes the complexity of each field using an estimator.

Estimators

GraphQL-Complexity provides various built-in estimators for computing query complexity:

SimpleEstimator

Estimate fields complexity based on constants for complexity and multiplier. This 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)

DirectivesEstimator

Define fields complexity using schema directives. This 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.

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)

Custom estimator

Custom estimators can be defined to compute the complexity of a field using the ComplexityEstimator interface.

from graphql_complexity import ComplexityEstimator


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

Supported libraries

This library is compatible with the following GraphQL libraries:

Strawberry GraphQL

The library is compatible with strawberry-graphql. Use the following command to install the library with Strawberry support:

poetry install --extras strawberry-graphql

To use the library with Strawberry GraphQL, 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 import SimpleEstimator
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(estimator=SimpleEstimator())
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.

graphql-complexity's People

Contributors

checho3388 avatar

Stargazers

Ezequiel Grondona avatar  avatar

Watchers

 avatar

graphql-complexity's Issues

Support introspection query

The complexity of introspection shouldn't be considered as any other query. Querying the schema should be cheap and thus ignored by the algorithm.

Create debug-server quick start entrypoint

Just like strawberry-graphql, having a debug-server extras option and a cli command to start a debug server with a demo schema annotated with directives would we great to have a first glance of the library.

For example, given an install like:

pip install graphql-complexity[debug-server]

Then we can hook strawberry debug server somehow with the complexity extension in place.

complexity start app

Consider `__typename` as MetaField with 0-complexity

__typename is not included as introspection type (

if unwrapped_type is not None and is_introspection_type(unwrapped_type):
) then it's considered as a complexity field. We should add a condition to catch those fields and consider them MetaField.

This test should pass to consider the bugfix done.

def test_typename_has_zero_complexity():
    query = """query {
        __typename
    }"""

    complexity = _evaluate_complexity(query)

    assert complexity == 0

Create a Path based Estimator

Given an input with field path and complexity such as:

query.hero=1
query.hero.id=1
query.hero.name=2
...

... or similar, the estimator should be able to calculate any query complexity by reading that data.
This estimator provides a centralized alternative to define each field's complexity instead of annotating the schema.

Some scenarios to handle:

  • Missing fields
  • Wildcards

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.