npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

graphql-rate-limit-directive

v2.0.5

Published

Fixed window rate-limiting directive for GraphQL. Use to limit repeated requests to queries and mutations.

Downloads

57,606

Readme

GraphQL Rate Limit

CircleCI Codecov npm Version npm Downloads Dependency Status

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

yarn add graphql-rate-limit-directive

You must also install peer dependencies:

yarn 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).

const { rateLimitDirective } = require('graphql-rate-limit-directive');

const { 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.

const { makeExecutableSchema } = require('@graphql-tools/schema');

let schema = makeExecutableSchema({
  typeDefs: [
    rateLimitDirectiveTypeDefs,
    /* plus any existing type definitions */
  ],
  /* ... */
});

schema = 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).

# Apply rate limiting to all fields of 'Query'
# Allow at most 60 queries per field within a minute
type Query @rateLimit(limit: 60, duration: 60) {
  ...
}

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.

# Apply default rate limiting to all fields of 'Query'
type Query @rateLimit(limit: 60, duration: 60) {
  books: [Book!]

  authors: [Author!]

  # Override behaviour imposed from 'Query' object on this field to have different limit
  quote: String @rateLimit(limit: 1, duration: 60)
}

Example

Additional, advanced examples are available in the examples folder:

const { makeExecutableSchema } = require('@graphql-tools/schema');
const { ApolloServer } = require('apollo-server');
const { ApolloServerPluginLandingPageGraphQLPlayground } = require('apollo-server-core');
const { rateLimitDirective } = require('graphql-rate-limit-directive');

const { rateLimitDirectiveTypeDefs, rateLimitDirectiveTransformer } = rateLimitDirective();

const resolvers = {
  Query: {
    books: () => [
      {
        title: 'A Game of Thrones',
        author: 'George R. R. Martin',
      },
      {
        title: 'The Hobbit',
        author: 'J. R. R. Tolkien',
      },
    ],
    quote: () =>
      'The future is something which everyone reaches at the rate of sixty minutes an hour, whatever he does, whoever he is. ― C.S. Lewis',
  },
};
let schema = makeExecutableSchema({
  typeDefs: [
    rateLimitDirectiveTypeDefs,
    `# Apply default rate limiting to all fields of 'Query'
    type Query @rateLimit(limit: 1, duration: 15) {
      books: [Book!]

      # Override behaviour imposed from 'Query' object on this field to have a custom limit
      quote: String @rateLimit(limit: 1)
    }

    type Book {
      # For each 'Book' where this field is requested, apply a rate limit
      title: String @rateLimit(limit: 72000, duration: 3600)

      # No limits are applied
      author: String
    }`,
  ],
  resolvers,
});
schema = rateLimitDirectiveTransformer(schema);

const server = new ApolloServer({
  schema,
  plugins: [
    ApolloServerPluginLandingPageGraphQLPlayground(),
  ]
});
server.listen().then(({ url }) => {
  console.log(`🚀  Server ready at ${url}`);
});

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