Installations
npm install graphql-rate-limit-directive
Releases
Unable to fetch releases
Developer
Developer Guide
Module System
CommonJS
Min. Node Version
Typescript Support
No
Node Version
20.10.0
NPM Version
10.2.3
Statistics
317 Stars
507 Commits
12 Forks
3 Watching
12 Branches
6 Contributors
Updated on 01 Nov 2024
Languages
TypeScript (99.48%)
JavaScript (0.52%)
Total Downloads
Cumulative downloads
Total Downloads
2,645,700
Last day
-4.1%
4,889
Compared to previous day
Last week
-5.3%
24,826
Compared to previous week
Last month
7.3%
109,804
Compared to previous month
Last year
2.9%
904,194
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
GraphQL Rate Limit
Fixed window rate limiting directive for GraphQL. Use to limit repeated requests to queries and mutations.
Features
- 👨💻 Identification: Distinguish requests using resolver data
- 🎯 Per-Object or Per-Field: Limit by objects and specific fields
- 📦 Storage: Supports multiple data store choices (Redis, process Memory, ...)
- ♾️ Throttles: Define any number of limits per field
- ⚙️ Extensions: Granular customization of field and response behaviour
- 😍 TypeScript: Written in and exports type definitions
Install
1yarn add graphql-rate-limit-directive
You must also install peer dependencies:
1yarn add rate-limiter-flexible graphql @graphql-tools/utils
How it works
GraphQL Rate Limit wraps resolvers, ensuring an action is permitted before it is invoked. A client is allocated a maximum of n
operations for every fixed size time window. Once the client has performed n
operations, they must wait.
Setup
Step 1: Define directive type definition and transformer
Import rateLimitDirective
and configure behaviour of directive (see options).
1const { rateLimitDirective } = require('graphql-rate-limit-directive'); 2 3const { rateLimitDirectiveTypeDefs, rateLimitDirectiveTransformer } = rateLimitDirective();
Step 2: Add directive to schema
Include rateLimitDirectiveTypeDefs
as part of the schema's type definitions.
Transform schema with rateLimitDirectiveTransformer
to apply implementation of directive.
1const { makeExecutableSchema } = require('@graphql-tools/schema'); 2 3let schema = makeExecutableSchema({ 4 typeDefs: [ 5 rateLimitDirectiveTypeDefs, 6 /* plus any existing type definitions */ 7 ], 8 /* ... */ 9}); 10 11schema = rateLimitDirectiveTransformer(schema);
Step 3: Attach directive to field or object
Attach @rateLimit
directive where desired. Argument limit
is number of allow operations per duration. Argument duration
is the length of the fixed window (in seconds).
1# Apply rate limiting to all fields of 'Query' 2# Allow at most 60 queries per field within a minute 3type Query @rateLimit(limit: 60, duration: 60) { 4 ... 5}
Overrides
When the directive is applied to a object, it rate limits each of its fields. A rate limit on a field will override a limit imposed by its parent type.
1# Apply default rate limiting to all fields of 'Query' 2type Query @rateLimit(limit: 60, duration: 60) { 3 books: [Book!] 4 5 authors: [Author!] 6 7 # Override behaviour imposed from 'Query' object on this field to have different limit 8 quote: String @rateLimit(limit: 1, duration: 60) 9}
Example
Additional, advanced examples are available in the examples folder:
- Context: isolating operations between users
- Points: customize the cost of a field resolution
- Redis: share state in a distrubuted environment
- Multiple: applying multiple rate limits on the same field
- onLimit Error: custom error raised
- onLimit Object: custom result instead of default resolution
- Field Extension: override behaviour per field using extensions
- Response Extension: rate limit details in response extension
1const { makeExecutableSchema } = require('@graphql-tools/schema'); 2const { ApolloServer } = require('apollo-server'); 3const { ApolloServerPluginLandingPageGraphQLPlayground } = require('apollo-server-core'); 4const { rateLimitDirective } = require('graphql-rate-limit-directive'); 5 6const { rateLimitDirectiveTypeDefs, rateLimitDirectiveTransformer } = rateLimitDirective(); 7 8const resolvers = { 9 Query: { 10 books: () => [ 11 { 12 title: 'A Game of Thrones', 13 author: 'George R. R. Martin', 14 }, 15 { 16 title: 'The Hobbit', 17 author: 'J. R. R. Tolkien', 18 }, 19 ], 20 quote: () => 21 'The future is something which everyone reaches at the rate of sixty minutes an hour, whatever he does, whoever he is. ― C.S. Lewis', 22 }, 23}; 24let schema = makeExecutableSchema({ 25 typeDefs: [ 26 rateLimitDirectiveTypeDefs, 27 `# Apply default rate limiting to all fields of 'Query' 28 type Query @rateLimit(limit: 1, duration: 15) { 29 books: [Book!] 30 31 # Override behaviour imposed from 'Query' object on this field to have a custom limit 32 quote: String @rateLimit(limit: 1) 33 } 34 35 type Book { 36 # For each 'Book' where this field is requested, apply a rate limit 37 title: String @rateLimit(limit: 72000, duration: 3600) 38 39 # No limits are applied 40 author: String 41 }`, 42 ], 43 resolvers, 44}); 45schema = rateLimitDirectiveTransformer(schema); 46 47const server = new ApolloServer({ 48 schema, 49 plugins: [ 50 ApolloServerPluginLandingPageGraphQLPlayground(), 51 ] 52}); 53server.listen().then(({ url }) => { 54 console.log(`🚀 Server ready at ${url}`); 55});
API
rateLimitDirective(options)
Create an implementation of a rate limit directive.
It is common to specify at least keyGenerator
and limiterClass
as part of options
.
Returns an object containing:
rateLimitDirectiveTypeDefs
: Schema Definition Language (SDL) representation of the directive.rateLimitDirectiveTransformer
: Function to apply the directive's logic to the provided schema.
name
Name of the directive.
Override the name of the directive, defaults to rateLimit
.
defaultLimit
Default value for argument limit.
Override the directive's limit
argument's default value, defaults to 60
.
defaultDuration
Default value for argument duration.
Override the directive's duration
argument's default value, defaults to 60
.
keyGenerator
Constructs a key to represent an operation on a field.
A key is generated to identify each request for each field being rate limited. To ensure isolation, the key is recommended to be unique per field. Supports both synchronous and asynchronous functions.
By default, it does not provide user or client independent rate limiting. See defaultKeyGenerator
and context example.
WARNING: Inside a generator function, consider accessing the GraphQL context
or memoizing any expensive calls (HTTP, database, ...) as the functions is run for each rate limited field.
limiterClass
An implementation of a limiter.
Storage implementations are provided by rate-limiter-flexible
.
Supports Redis, process Memory, Cluster or PM2, Memcached, MongoDB, MySQL, PostgreSQL to control requests rate in single process or distributed environment.
Memory store is the default but not recommended for production as it does not share state with other servers or processes. See Redis example for use in a distributed environment.
limiterOptions
Configuration to apply to created limiters.
WARNING: If providing the keyPrefix
option, consider using directive's name as part of the prefix to ensure isolation between different directives.
pointsCalculator
Calculate the number of points to consume.
Default with defaultPointsCalculator
is to cost one point.
- A positve number reduces the remaining points for consumption for one duration.
- A zero skips consuming points (like an allowlist).
- A negative number increases the available points for consumption for one duration.
onLimit
Behaviour when limit is exceeded.
Throw an error or return an object describing a reached limit and when it will reset. Default is to throw an error using defaultOnLimit
. See error example and object example.
setState
If rate limiter information for request should be stored in context, how to record it.
When provided, puts the rate limit information for the current operation into context
.
Can be used to include formatted rate limit information in a response's extensions
, see example.
defaultKeyGenerator(directiveArgs, source, args, context, info)
Get a value to uniquely identify a field in a schema.
A field is identified by the key ${info.parentType}.${info.fieldName}
. This does not provide user or client independent rate limiting. User A could consume all the capacity and starve out User B.
This function can be used in conjunction with context
information to ensure user/client isolation. See context example.
directiveArgs
The arguments defined in the schema for the directive.
source
The previous result returned from the resolver on the parent field.
args
The arguments provided to the field in the GraphQL operation.
context
Contains per-request state shared by all resolvers in a particular operation.
info
Holds field-specific information relevant to the current operation as well as the schema details.
defaultPointsCalculator(directiveArgs, source, args, context, info)
Calculate the number of points to consume.
Cost one point.
directiveArgs
The arguments defined in the schema for the directive.
source
The previous result returned from the resolver on the parent field.
args
The arguments provided to the field in the GraphQL operation.
context
Contains per-request state shared by all resolvers in a particular operation.
info
Holds field-specific information relevant to the current operation as well as the schema details.
defaultOnLimit(response, directiveArgs, source, args, context, info)
Raise a rate limit error when there are too many requests.
Throws a GraphQLError
with message Too many requests, please try again in N seconds.
response
The current rate limit information for this field.
directiveArgs
The arguments defined in the schema for the directive.
source
The previous result returned from the resolver on the parent field.
args
The arguments provided to the field in the GraphQL operation.
context
Contains per-request state shared by all resolvers in a particular operation.
info
Holds field-specific information relevant to the current operation as well as the schema details.
defaultSetState(name)
Write directive state into context.
How to store the latest rate limit response in context
, using schema coordinates.
name
Name of the directive.
Contributions
Contributions, issues and feature requests are very welcome.
If you are using this package and fixed a bug for yourself, please consider submitting a PR!
License
MIT © Rob Van Gennip
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
license file detected
Details
- Info: project has a license file: LICENSE:0
- Info: FSF or OSI recognized license: MIT License: LICENSE:0
Reason
Found 1/5 approved changesets -- score normalized to 2
Reason
0 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 30 are checked with a SAST tool
Reason
12 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-qwcr-r2fm-qrc7
- Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x
- Warn: Project is vulnerable to: GHSA-rv95-896h-c2vc
- Warn: Project is vulnerable to: GHSA-qw6h-vgh9-j6wx
- Warn: Project is vulnerable to: GHSA-9pv7-vfvm-6vr7
- Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j
- Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg
- Warn: Project is vulnerable to: GHSA-cm22-4g7w-348p
- Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg
- Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275
- Warn: Project is vulnerable to: GHSA-f6v4-cf5j-vf3w
- Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv
Score
2.3
/10
Last Scanned on 2024-11-18
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More