GraphQL-Rate-Limit

A GraphQL Directive For Rate Limiting Your Resolvers 💂‍♀️

💂‍♀️ 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 {
  # Rate limit to 5 per second
  getItems: [Item] @rateLimit(window: "1s", max: 5)

  # Rate limit access per item ID
  getItem(id: ID!): Item @rateLimit(identityArgs: ["id"])
}

type Mutation {
  # Rate limit with a custom error message
  createItem(title: String!): Item @rateLimit(message: "You are doing that too often.")

  # Rate limit access per item.id
  updateItem(item: Item!): Item @rateLimit(identityArgs: ["item.id"])
}

Usage

Step 1.

Create a configured GraphQLRateLimit class.

const { createRateLimitDirective } = require('graphql-rate-limit');
// OR
import { createRateLimitDirective } from 'graphql-rate-limit';

const GraphQLRateLimit = createRateLimitDirective({
  /**
   * `identifyContext` is required and used to identify the user/client. The most likely cases
   * are either using the context's request.ip, or the user ID on the context.
   * A function that accepts the context and returns a string that is used to identify the user.
   */
  identifyContext: (ctx) => ctx.user.id, // Or could be something like: return ctx.req.ip;
  /**
   * `store` is optional as it defaults to an InMemoryStore. See the implementation of InMemoryStore if 
   * you'd like to implement your own with your own database.
   */
  store: new MyCustomStore(),
  /**
   * Generate a custom error message. Note that the `message` passed in to the directive will be used 
   * if its set.
   */
  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.

# This must be added to the top of your schema.
directive @rateLimit(
  max: Int, 
  window: String,
  message: String, 
  identityArgs: [String], 
) on FIELD_DEFINITION

type Query {
  # Limit queries to getThings to 10 per minute.
  getThings: [Thing] @rateLimit(max: 10, window: "6s")
}

type Query {
  # Limit attempts to login with a particular email to 10 per 2 hours.
  login(email: String!, password: String!): String @rateLimit(max: 10, window: "2h", identityArgs: ["email"])
}

Subscribe to the Newsletter

Get our latest news,tutorials,guides,tips & deals delivered to your inbox.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

shares