async-graphql/docs/zh-CN/src/depth_and_complexity.md
2020-12-18 23:10:57 +08:00

107 lines
2.7 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 查询的深度和复杂度
GraphQL提供了非常灵活的查询方法但在客户端上滥用复杂的查询可能造成风险限制查询语句的深度和复杂度可以减轻这种风险。
## 昂贵的查询
考虑一种允许列出博客文章的架构。每个博客帖子也与其他帖子相关。
```graphql
type Query {
posts(count: Int = 10): [Post!]!
}
type Post {
title: String!
text: String!
related(count: Int = 10): [Post!]!
}
```
创建一个会引起很大响应的查询不是很困难:
```graphql
{
posts(count: 100) {
related(count: 100) {
related(count: 100) {
related(count: 100) {
title
}
}
}
}
}
```
响应的大小随`related`字段的每个其他级别呈指数增长。幸运的是,`Async-graphql`提供了一种防止此类查询的方法。
## 限制查询的深度
查询的深度是字段嵌套的层数,下面是一个深度为`3`的查询。
```graphql
{
a {
b {
c
}
}
}
```
在创建`Schema`的时候可以限制深度,如果查询语句超过这个限制,则会出错并且返回`Query is nested too deep.`消息。
```rust
let schema = Schema::build(Query, EmptyMutation, EmptySubscription)
.limit_depth(5) // 限制最大深度为5
.finish();
```
## 限制查询的复杂度
复杂度是查询语句中字段的数量,每个字段的复杂度默认为`1`,下面是一个复杂度为`6`的查询。
```graphql
{
a b c {
d {
e f
}
}
}
```
在创建`Schema`的时候可以限制复杂度,如果查询语句超过这个限制,则会出错并且返回`Query is too complex.`。
```rust
let schema = Schema::build(Query, EmptyMutation, EmptySubscription)
.limit_complexity(5) // 限制最大深度为5
.finish();
```
## 自定义字段的复杂度
针对非列表类型和列表类型的字段,有两种自定义复杂度的方法。
下面的代码中,`value`字段的复杂度为`5`。而`values`字段的复杂度为`count * child_complexity``child_complexity`是一个特殊的变量,表示子查询的复杂度,
`count`是字段的参数,这个表达式用于计算`values`字段的复杂度,并且返回值的类型必须是`usize`。
```rust
struct Query;
#[Object]
impl Query {
#[graphql(complexity = 5)]
async fn value(&self) -> i32 {
todo!()
}
#[graphql(complexity = "count * child_complexity")]
async fn values(&self, count: usize) -> i32 {
todo!()
}
}
```
**注意: 计算复杂度是在验证阶段完成而不是在执行阶段,所以你不用担心超限的查询语句会导致查询只执行一部分。**