@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
JavaScript
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()]);
}