|
7 | 7 | </div> |
8 | 8 |
|
9 | 9 | |
10 | | -## Summary |
| 10 | +## Summary |
11 | 11 |
|
12 | | -Developed under tech-accelerator [OSLabs](https://opensourcelabs.io/), GraphQLGate strives for a principled approach to complexity analysis and rate-limiting for GraphQL queries by accurately estimating an upper-bound of the response size of the query. Within a loosely opinionated framework with lots of configuration options, you can reliably throttle GraphQL queries by complexity and depth to protect your GraphQL API. Our solution is inspired by [this paper](https://github.com/Alan-Cha/fse20/blob/master/submissions/functional/FSE-24/graphql-paper.pdf) from IBM research teams. |
| 12 | +Developed under tech-accelerator [OSLabs](https://opensourcelabs.io/), GraphQLGate strives for a principled approach to complexity analysis and rate-limiting for GraphQL queries by accurately estimating an upper-bound of the response size of the query. Within a loosely opinionated framework with lots of configuration options, you can reliably throttle GraphQL queries by complexity and depth to protect your GraphQL API. Our solution is inspired by [this paper](https://github.com/Alan-Cha/fse20/blob/master/submissions/functional/FSE-24/graphql-paper.pdf) from IBM research teams. |
13 | 13 |
|
14 | 14 | ## Table of Contents |
15 | 15 |
|
@@ -201,29 +201,79 @@ This package exposes 3 additional functionalities which comprise the internals o |
201 | 201 |
|
202 | 202 | ### Complexity Analysis |
203 | 203 |
|
204 | | -1. #### `typeWeightsFromSchema` | create the type weight object from the schema for complexity analysis |
205 | | - - `schema: GraphQLSchema` | GraphQL schema object |
206 | | - - `typeWeightsConfig: TypeWeightConfig = defaultTypeWeightsConfig` | type weight configuration |
207 | | - - `enforceBoundedLists = false` |
208 | | - - returns: `TypeWeightObject` |
| 204 | +1. #### `typeWeightsFromSchema` | function to create the type weight object from the schema for complexity analysis |
209 | 205 |
|
210 | | -2. #### `ComplexityAnalysis` | calculate the complexity of the query based on the type weights and variables |
211 | | - - `typeWeights: TypeWeightObject` |
212 | | - - `variables: Variables` | variables on request |
213 | | - - returns a class with method: |
214 | | - - `processQuery(queryAST: DocumentNode): number` |
215 | | - - returns: complexity of the query and exposes `maxDepth` property for depth limiting |
| 206 | + - `schema: GraphQLSchema` | GraphQL schema object |
| 207 | + - `typeWeightsConfig: TypeWeightConfig = defaultTypeWeightsConfig` | type weight configuration |
| 208 | + - `enforceBoundedLists = false` |
| 209 | + - returns: `TypeWeightObject` |
| 210 | + - usage: |
| 211 | + |
| 212 | + ```ts |
| 213 | + import { typeWeightsFromSchema } from 'graphql-limiter'; |
| 214 | + import { GraphQLSchema } from 'graphql/type/schema'; |
| 215 | + |
| 216 | + let schema: GraphQLSchema = buildSchema(`...`); |
| 217 | + |
| 218 | + const typeWeights: TypeWeightObject = typeWeightsFromSchema(schema); |
| 219 | + ``` |
| 220 | + |
| 221 | +2. #### `ComplexityAnalysis` | class to calculate the complexity of the query based on the type weights and variables |
| 222 | + |
| 223 | + - `typeWeights: TypeWeightObject` |
| 224 | + - `variables: Variables` | variables on request |
| 225 | + - returns a class with method: |
| 226 | + |
| 227 | + - `processQuery(queryAST: DocumentNode): number` |
| 228 | + - returns: complexity of the query and exposes `maxDepth` property for depth limiting |
| 229 | + - usage: |
| 230 | + |
| 231 | + ```ts |
| 232 | + import { typeWeightsFromSchema } from 'graphql-limiter'; |
| 233 | + import { parse } from 'graphql'; |
| 234 | + |
| 235 | + let query: DocumentNode = parse(`...`); |
| 236 | + |
| 237 | + const queryParser: ASTParser = new ComplexityAnalysis(typeWeights, variables); |
| 238 | + |
| 239 | + const complexity: number = queryParser.parse(query); |
| 240 | + ``` |
216 | 241 |
|
217 | 242 | ### Rate-limiting |
218 | 243 |
|
219 | | -3. #### `rateLimiter` | returns a rate limiting implementation based on selections |
220 | | - - `rateLimiter: RateLimiterConfig` | see "configuration" -> rateLimiter |
221 | | - - `client: Redis` | an ioredis client |
222 | | - - `keyExpiry: number` | time (ms) for key to persist in cache |
223 | | - - returns a class with method: |
224 | | - - `processRequest(uuid: string, timestamp: number, tokens = 1): Promise<RateLimiterResponse>` |
225 | | - - returns: `{ success: boolean, tokens: number, retryAfter?: number }` | where tokens is tokens available, retryAfter is time to wait in seconds before the request would be successful and success is false if the request is blocked |
| 244 | +3. #### `rateLimiter` | returns a rate limiting class instance based on selections |
| 245 | + |
| 246 | + - `rateLimiter: RateLimiterConfig` | see "configuration" -> rateLimiter |
| 247 | + - `client: Redis` | an ioredis client |
| 248 | + - `keyExpiry: number` | time (ms) for key to persist in cache |
| 249 | + - returns a class with method: |
| 250 | + |
| 251 | + - `processRequest(uuid: string, timestamp: number, tokens = 1): Promise<RateLimiterResponse>` |
| 252 | + - returns: `{ success: boolean, tokens: number, retryAfter?: number }` | where tokens is tokens available, retryAfter is time to wait in seconds before the request would be successful and success is false if the request is blocked |
| 253 | + |
| 254 | + usage: |
| 255 | + |
| 256 | + ```ts |
| 257 | + import { rateLimiter } from 'graphql-limiter'; |
| 258 | +
|
| 259 | + const limiter: RateLimiter = rateLimiter( |
| 260 | + { |
| 261 | + type: 'TOKEN_BUCKET', |
| 262 | + refillRate: 1, |
| 263 | + capacity: 10, |
| 264 | + }, |
| 265 | + typeWeights, |
| 266 | + true |
| 267 | + ); |
| 268 | +
|
| 269 | + const response: RateLimiterResponse = limiter.processRequest( |
| 270 | + 'user-1', |
| 271 | + new Date().valueOf(), |
| 272 | + 5 |
| 273 | + ); |
226 | 274 |
|
| 275 | + const complexity: number = queryParser.parse(query); |
| 276 | + ``` |
227 | 277 |
|
228 | 278 | ## <a name="future-development"></a> Future Development |
229 | 279 |
|
|
0 commit comments