You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+19-18Lines changed: 19 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -81,7 +81,7 @@ app.use(
81
81
82
82
-`depthLimit: number` | throttle queies by the depth of the nested stucture | defaults to `Infinity` (ie. no limit)
83
83
-`enforceBoundedLists: boolean` | if true, an error will be thrown if any lists types are not bound by slicing arguments [`first`, `last`, `limit`] or directives | defaults to `false`
84
-
-`dark: boolean` | if true, the package will calculate complexity, depth and tokens but not throttle any queries. Use this to dark launch the package and monitor the rate limiter's impact without limiting user requests.
84
+
-`dark: boolean` | if true, the package will calculate complexity, depth and tokens but not throttle any queries. Use this to dark launch the package and monitor the rate limiter's impact without limiting user requests.
85
85
86
86
All configuration options
87
87
@@ -109,26 +109,27 @@ app.use(
109
109
dark:false, // defaults to false
110
110
depthLimit:7// defaults to Infinity (ie. no depth limiting)
111
111
});
112
-
```
113
-
112
+
```
113
+
114
114
## <a name="lists"></a> Notes on Lists
115
115
116
-
For queries that return a list, the complexity can be determined with schema directives, or by providing a slicing argument to the query (`first`, `last`, `limit).
116
+
For queries that return a list, the complexity can be determined by providing a slicing argument to the query (`first`, `last`, `limit`), or using a schema directive.
117
117
118
118
1. Slicing arguments: lists must be bounded by one integer slicing argument in order to calculate the complexity for the field. Thispackage supports the slicing arguments`first`, `last` and `limit`. The complexity of the list will be the value passed as the argument to the field.
119
119
120
-
2. Directives: ... TODO ...
121
-
120
+
2. Directives: First, `@listCost` must be defined in your schema with`directive @listCost(cost: Int!) on FIELD_DEFINITION`. Then, on any unbounded list field, add `@listCost(cost: Int)` and pass into `Int` the complexity you want applied whenever the list is queried.
121
+
122
+
(Note: Slicing arguments are preferred!`@listCost` is in place for any reason slicing arguments cannot be used.)
122
123
123
124
## <a name="how-it-works"></a> How It Works
124
125
125
126
Requests are rate-limited based on the IP address associated with the request.
126
127
127
-
On server start, the GraphQL (GQL) schema is parsed to build an object that maps GQL types/fields to their corresponding weights. Type weights can be provided during <ahref="typeWeights">initial configuration</a>. When a request is received, this object is used to cross reference the fields queried by the user and compute the complexity of each field. The total complexity of the request is the sum of these values.
128
+
On server start, the GraphQL (GQL) schema is parsed to build an object that maps GQL types/fields to their corresponding weights. Type weights can be provided during <a href="typeWeights">initial configuration</a>. When a request is received, this object is used to cross reference the fields queried by the user and compute the complexity of each field. The total complexity of the request is the sum of these values.
128
129
129
130
Complexity is determined, statically (before any resolvers are called) to estimate the upper bound of the response size - a proxy for the work done by the server to build the response. The total complexity is then used to allow/block the request based on popular rate-limiting algorithms.
130
131
131
-
Requests for each user are processed sequentially by the rate limiter.
132
+
Requests for each user are processed sequentially by the rate limiter.
132
133
133
134
Example (with default weights):
134
135
@@ -144,20 +145,20 @@ query { // 1 (complexity)
144
145
}
145
146
reviews(episode: EMPIRE, limit: 5) { // 5
146
147
stars // stars 0
147
-
commentary // commentary 0
148
-
}
148
+
commentary // commentary 0
149
+
}
149
150
}
150
151
// total complexity of 10
151
152
```
152
153
153
154
## <a name="response"></a> Response
154
155
155
-
1. <b>Blocked Requests</b>: blocked requests recieve a response with,
156
+
1.<b>Blocked Requests</b>: blocked requests recieve a response with,
157
+
158
+
- status of`429`for`Too Many Requests`
159
+
-`Retry-After` header with a value of the time to wait in seconds before the request would be approved (`Infinity`if the complexity is greater than rate-limiting capacity).
160
+
-AJSON response with the `tokens` available, `complexity`of the query, `depth`of the query, `success`of the query set to `false`, and the UNIX`timestamp`of the request
156
161
157
-
- status of `429` for `Too Many Requests`
158
-
-`Retry-After` header with a value of the time to wait in seconds before the request would be approved (`Infinity` if the complexity is greater than rate-limiting capacity).
159
-
- A JSON response with the `tokens` available, `complexity` of the query, `depth` of the query, `success` of the query set to `false`, and the UNIX `timestamp` of the request
160
-
161
162
2.<b>Successful Requests</b>: successful requests are passed onto the next function in the middleware chain with the following properties saved to `res.locals`
162
163
163
164
```javascript
@@ -174,8 +175,8 @@ query { // 1 (complexity)
174
175
175
176
## <a name="error-handling"></a> Error Handling
176
177
177
-
- Incoming queries are validated against the GraphQL schema. If the query is invalid, a response with status code `400` is returned along with an array of GraphQL Errors that were found.
178
-
- To avoid disrupting server activity, errors thrown during the analysis and rate-limiting of the query are logged and the request is passed onto the next middleware function in the chain.
178
+
- Incoming queries are validated against the GraphQL schema. If the query is invalid, a response with status code `400` is returned along with an array of GraphQL Errors that were found.
179
+
- To avoid disrupting server activity, errors thrown during the analysis and rate-limiting of the query are logged and the request is passed onto the next middleware function in the chain.
179
180
180
181
## <a name="future-development"></a> Future Development
181
182
@@ -184,7 +185,7 @@ query { // 1 (complexity)
184
185
- Implement leaky bucket algorithm for rate-limiting
185
186
- Experiment with performance improvements
186
187
- caching optimization
187
-
- Ensure connection pagination conventions can be accuratly acconuted for in complexity analysis
188
+
- Ensure connection pagination conventions can be accuratly acconuted for in complexity analysis
188
189
- Ability to use middleware with other server frameworks
0 commit comments