Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query Complexity #80

Closed
michaelstaib opened this issue Jun 15, 2018 · 11 comments
Closed

Query Complexity #80

michaelstaib opened this issue Jun 15, 2018 · 11 comments
Assignees
Labels
🎉 enhancement New feature or request
Milestone

Comments

@michaelstaib
Copy link
Member

This feature shall provide more security options to the execution engine.

Sometimes, the depth of a query is not enough to truly know how large or expensive a GraphQL query will be. In a lot of cases, certain fields in our schema are known to be more complex to compute than others.
Query complexity allows you to define how complex these fields are, and to restrict queries with a maximum complexity. The idea is to define how complex each field is by using a simple number. A common default is to give each field a complexity of 1. Take this query for example:

query {
  author(id: "abc") { # complexity: 1
    posts {           # complexity: 1
      title           # complexity: 1
    }
  }
}

A simple addition gives us a total of 3 for the complexity of this query. If we were to set a max complexity of 2 on our schema, this query would fail.
What if the posts field is actually much more complex than the author` field? We can set a different complexity to the field. We can even set a different complexity depending on arguments! Let’s take a look at a similar query, where posts has a variable complexity depending on its arguments:

query {
  author(id: "abc") {    # complexity: 1
    posts(first: 5) {    # complexity: 5
      title              # complexity: 1
    }
  }
}

Query Complexity Pros

  • Covers more cases than a simple query depth.
  • Reject queries before executing them by statically analyzing the complexity.

Query Complexity Cons

  • Hard to implement perfectly.
  • If complexity is estimated by developers, how do we keep it up to date? How do we find the costs in the first place?
  • Mutations are hard to estimate. What if they have a side effect that is hard to measure like queuing a background job?

https://www.howtographql.com/advanced/4-security/

@michaelstaib michaelstaib added 🎉 enhancement New feature or request 🔍 investigate Indicates that an issue or pull request needs more information. labels Jun 15, 2018
@michaelstaib michaelstaib added this to the 1.0.0 milestone Jun 15, 2018
@michaelstaib
Copy link
Member Author

@michaelstaib michaelstaib modified the milestones: 1.0.0, 0.7.0 Nov 11, 2018
@michaelstaib michaelstaib added in progress and removed 🔍 investigate Indicates that an issue or pull request needs more information. labels Dec 20, 2018
@michaelstaib
Copy link
Member Author

This is a nice way to annotate complexity and specify the multipliers.

type Participant {
  # The complexity of getting one thread in a thread connection is 3, and multiply that by the amount of threads fetched
  threadConnection(first: PaginationAmount, after: String): ThreadConnection @cost(complexity: 3, multipliers: ["first"])
}

type Thread {
  author: Author @cost(complexity: 1)
  participants(first: PaginationAmount,...): [Participant] @cost(complexity: 2, multipliers: ["first"])
}

@michaelstaib
Copy link
Member Author

Multipliers should be limited to built-in scalar types since the variables are not coerced at the time we validate. Since we have the schema we could coerce simple variables on the go.

@michaelstaib
Copy link
Member Author

@michaelstaib
Copy link
Member Author

Look also at what the GitHub guys did.

@michaelstaib
Copy link
Member Author

I will add support for variables to the validation rules.

@michaelstaib
Copy link
Member Author

#456

@michaelstaib
Copy link
Member Author

@michaelstaib michaelstaib pinned this issue Jan 5, 2019
@michaelstaib
Copy link
Member Author

Fields can be annotated with the @cost directive. The @costdirective contains two arguments, complexity which is the general complexity for this field and multipliers which are a list of arguments of the field that multiply the complexity by default.

The algorithm for field complexity can be replaced by a custom algorithm. The complexity algorithm can be defined for all fields or one can opt to add a specific algorithm for specific fields.

builder.AddOperationComplexityRule((field, complexity, multipliers) => 
{
  // ... custom code
});

or

builder.AddOperationComplexityRule(
    "TypeName",
    "FieldName",
    (field, complexity, multipliers) => 
    {
      // ... custom code
    });

@michaelstaib
Copy link
Member Author

This issue was closed by accident.

@michaelstaib
Copy link
Member Author

This one is now implemented

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🎉 enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants