Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

can we have a Throttle method decorator with access to the injectable instance? #2002

Open
1 task done
ticmaisdev opened this issue Jun 6, 2024 · 1 comment
Open
1 task done

Comments

@ticmaisdev
Copy link

ticmaisdev commented Jun 6, 2024

Is there an existing issue that is already proposing this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe it

I'm assuming we can only set @Throttle options before compile time since this decorator doesn't have access to the @Injectable instance.

Describe the solution you'd like

I would like to have something like this:

/**
 * This is a custom method decorator which is used to limit the rate
 * at which a function can fire.
 *
 * This is going to override specific throttler configurations, at the specific method.
 *
 * @template T - The type of the instance.
 *
 * @param {Function} cb - A callback that provides the instance class with injected services,
 * so it's possible to set throttle options at run time.
 */
export const Throttle = <T>(
  cb: (instance: T) => Record<string, ThrottlerMethodOrControllerOptions>,
) => {
  return function (
    target: T,
    propertyKey: string,
    descriptor: PropertyDescriptor,
  ) {
    const originalMethod = descriptor.value;

    descriptor.value = function (...args: any[]) {
      const throttleOptions = cb(this);
      NestThrottle(throttleOptions)(
        target,
        propertyKey,
        descriptor,
      );
      return originalMethod.apply(this, args);
    };

    return descriptor;
  };
};


@Injectable()
export class MyController {
  readonly config: EnvironmentVariables;

  constructor(
    private readonly configService: ConfigService<InferEnvironmentVariables>,){
    const config = { ...this.configService.getOrThrow('all', { infer: true }) };
    this.config = config;
  }

  @Throttle<MyController>((instance) => ({
    default: {
      limit: instance.config.rps.upload,
      ttl: 1000,
    }
  }))
  async upload(/* omitted */): Promise<any> {
    /* omitted */
  }
}

Teachability, documentation, adoption, migration strategy

I'm aware this decorator can be improved.

What is the motivation / use case for changing the behavior?

I've got a default throttling rule that applies to all routes, but some routes need specific options due to security issues. Although, as of now, it's not possible to set these rules dynamically.

With described solution we can dynamically set these options and comply with https://12factor.net. This would allow us to change throttling rules without the need to re-compile the app.

@ticmaisdev
Copy link
Author

ticmaisdev commented Jun 6, 2024

Another approach could be @PickThrottle('default') or @PickThrottle('foobar').

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant