|
| 1 | +import { RedisClientOptions } from 'redis'; |
| 2 | +import { Request, Response, NextFunction, RequestHandler } from 'express'; |
| 3 | +import { GraphQLSchema } from 'graphql/type/schema'; |
| 4 | +import { defaultTypeWeightsConfig } from '../analysis/buildTypeWeights'; |
| 5 | + |
| 6 | +// FIXME: Will the developer be responsible for first parsing the schema from a file? |
| 7 | +// Can consider accepting a string representing a the filepath to a schema |
| 8 | +// FIXME: Should a 429 status be sent by default or do we allow the user to handle blocked requests? |
| 9 | + |
| 10 | +/** |
| 11 | + * Primary entry point for adding GraphQL Rate Limiting middleware to an Express Server |
| 12 | + * @param {RateLimiterSelection} rateLimiter Specify rate limiting algorithm to be used |
| 13 | + * @param {RateLimiterOptions} options Specify the appropriate options for the selected rateLimiter |
| 14 | + * @param {GraphQLSchema} schema GraphQLSchema object |
| 15 | + * @param {RedisClientOptions} redisClientOptions valid node-redis connection options. See https://github.com/redis/node-redis/blob/HEAD/docs/client-configuration.md |
| 16 | + * @param {TypeWeightConfig} typeWeightConfig Optional type weight configuration for the GraphQL Schema. |
| 17 | + * Defaults to {mutation: 10, object: 1, field: 0, connection: 2} |
| 18 | + * @returns {RequestHandler} express middleware that computes the complexity of req.query and calls the next middleware |
| 19 | + * if the query is allowed or sends a 429 status if the request is blocked |
| 20 | + * @throws ValidationError if GraphQL Schema is invalid |
| 21 | + */ |
| 22 | +export function expressRateLimiter( |
| 23 | + rateLimiter: RateLimiterSelection, |
| 24 | + rateLimiterOptions: RateLimiterOptions, |
| 25 | + schema: GraphQLSchema, |
| 26 | + redisClientOptions: RedisClientOptions, |
| 27 | + typeWeightConfig: TypeWeightConfig = defaultTypeWeightsConfig |
| 28 | +): RequestHandler { |
| 29 | + // TODO: Set 'timestamp' on res.locals to record when the request is received in UNIX format. HTTP does not inlude this. |
| 30 | + // TODO: Parse the schema to create a TypeWeightObject. Throw ValidationError if schema is invalid |
| 31 | + // TODO: Connect to Redis store using provided options. Default to localhost:6379 |
| 32 | + // TODO: Configure the selected RateLimtier |
| 33 | + // TODO: Configure the complexity analysis algorithm to run for incoming requests |
| 34 | + |
| 35 | + const middleware: RequestHandler = (req: Request, res: Response, next: NextFunction) => { |
| 36 | + // TODO: Parse query from req.query, compute complexity and pass necessary info to rate limiter |
| 37 | + // TODO: Call next if query is successful, send 429 status if query blocked, call next(err) with any thrown errors |
| 38 | + next(Error('Express rate limiting middleware not implemented')); |
| 39 | + }; |
| 40 | + return middleware; |
| 41 | +} |
| 42 | + |
| 43 | +export default expressRateLimiter; |
0 commit comments