💂♀️ GraphQL Rate Limit 💂♂️
A GraphQL directive to add basic but granular rate limiting to your Queries or Mutations.
Features
- 💂♀️ Add rate limits to queries or mutations
- 🔑 Add filters to rate limits based on the query or mutation args
- ❌ Custom error messaging
- ⏰ Configure using a simple
max
per window
arguments - 💼 Custom stores, use Redis, Postgres, Mongo... it defaults to in-memory
- 💪 Written in TypeScript
Install
yarn add graphql-rate-limit
Example
directive @rateLimit(
max: Int,
window: String,
message: String,
identityArgs: [String],
) on FIELD_DEFINITION
type Query {
getItems: [Item] @rateLimit(window: "1s", max: 5)
getItem(id: ID!): Item @rateLimit(identityArgs: ["id"])
}
type Mutation {
createItem(title: String!): Item @rateLimit(message: "You are doing that too often.")
updateItem(item: Item!): Item @rateLimit(identityArgs: ["item.id"])
}
Usage
Step 1.
Create a configured GraphQLRateLimit class.
const { createRateLimitDirective } = require('graphql-rate-limit');
import { createRateLimitDirective } from 'graphql-rate-limit';
const GraphQLRateLimit = createRateLimitDirective({
identifyContext: (ctx) => ctx.user.id,
store: new MyCustomStore(),
formatError: ({ fieldName }) => {
return `Woah there, you are doing way too much ${fieldName}`
}
});
Step 2.
Add GraphQLRateLimit to your GraphQL server configuration. Example using Apollo Server:
const server = new ApolloServer({
typeDefs,
resolvers,
schemaDirectives: {
rateLimit: GraphQLRateLimit
}
});
Note: If you are calling makeExecutableSchema
directly and passing in the schema
key to ApolloServer or similar, you should do the following:
const schema = makeExecutableSchema({
typeDefs,
resolvers
schemaDirectives: {
rateLimit: GraphQLRateLimit
}
});
const graphql = new ApolloServer({ schema });
Step 3.
Use in your GraphQL Schema.
directive @rateLimit(
max: Int,
window: String,
message: String,
identityArgs: [String],
) on FIELD_DEFINITION
type Query {
getThings: [Thing] @rateLimit(max: 10, window: "6s")
}
type Query {
login(email: String!, password: String!): String @rateLimit(max: 10, window: "2h", identityArgs: ["email"])
}
Directive args
window
Specify a time interval window that the max
number of requests can access the field. We use Zeit's ms
to parse the window
arg, docs here.
max
Define the max number of calls to the given field per window
.
identityArgs
If you wanted to limit the requests to a field per id, per user, use identityArgs
to define how the request should be identified. For example you'd provide just ["id"]
if you wanted to rate limit the access to a field by id
. We use Lodash's get
to access nested identity args, docs here.
message
A custom message per field. Note you can also use formatError
to customise the default error message if you don't want to define a single message per rate limited field.
Redis Store Usage
It is recommended to use a persistent store rather than the default InMemoryStore. GraphQLRateLimit currently supports Redis as an alternative. You'll need to install Redis in your project first.
import { createRateLimitDirective, RedisStore } from 'graphql-rate-limit';
const GraphQLRateLimit = createRateLimitDirective({
identifyContext: ctx => ctx.user.id,
store: new RedisStore(redis.createClient())
});