UNPKG

@envelop/rate-limiter

Version:

This plugins uses [`graphql-rate-limit`](https://github.com/teamplanes/graphql-rate-limit#readme) in order to limit the rate of calling queries and mutations.

61 lines (60 loc) 2.73 kB
import { useOnResolve } from '@envelop/on-resolve'; import { getDirective } from './utils.js'; import { getGraphQLRateLimiter } from 'graphql-rate-limit'; export * from './utils.js'; export class UnauthenticatedError extends Error { } export const DIRECTIVE_SDL = /* GraphQL */ ` directive @rateLimit(max: Int, window: String, message: String) on FIELD_DEFINITION `; export const useRateLimiter = (options) => { const rateLimiterFn = getGraphQLRateLimiter({ identifyContext: options.identifyFn }); return { onPluginInit({ addPlugin }) { addPlugin(useOnResolve(async ({ args, root, context, info }) => { const rateLimitDirectiveNode = getDirective(info, options.rateLimitDirectiveName || 'rateLimit'); if (rateLimitDirectiveNode && rateLimitDirectiveNode.arguments) { const maxNode = rateLimitDirectiveNode.arguments.find(arg => arg.name.value === 'max') ?.value; const windowNode = rateLimitDirectiveNode.arguments.find(arg => arg.name.value === 'window') ?.value; const messageNode = rateLimitDirectiveNode.arguments.find(arg => arg.name.value === 'message') ?.value; const message = messageNode.value; const max = parseInt(maxNode.value); const window = windowNode.value; const id = options.identifyFn(context); const errorMessage = await context.rateLimiterFn({ parent: root, args, context, info }, { max, window, message: interpolate(message, { id, }), }); if (errorMessage) { if (options.onRateLimitError) { options.onRateLimitError({ error: errorMessage, identifier: id, context, info, }); } if (options.transformError) { throw options.transformError(errorMessage); } throw new Error(errorMessage); } } })); }, async onContextBuilding({ extendContext }) { extendContext({ rateLimiterFn, }); }, }; }; function interpolate(message, args) { return message.replace(/\{{([^)]*)\}}/g, (_, key) => args[key.trim()]); }