I have 2 repos, one is my host repo, and one is where my throttler is present.
In the host repo I have my throttler as a dependency in my package.json.
I have 2 files in the throttler package:
GqlThrottlerGuard:
@Injectable()
export class GqlThrottlerGuard extends ThrottlerGuard {
getRequestResponse(context: ExecutionContext): { res: Response; req: Request } {
if (context.getType<GqlContextType>() === 'graphql') {
const gqlCtx = GqlExecutionContext.create(context);
const ctx = gqlCtx.getContext();
return { req: ctx.req, res: ctx.req.res };
}
const ctx = context.switchToHttp();
return { req: ctx.getRequest(), res: ctx.getRequest() };
}
}
GraphqlThrottlerModule:
@Module({
imports: [
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => [
{
ttl: +config.get('THROTTLE_TTL'),
limit: +config.get('THROTTLE_LIMIT'),
},
],
}),
],
providers: [GqlThrottlerGuard],
exports: [GqlThrottlerGuard],
})
export class GraphqlThrottlerModule {}
And my throttler package.json:
{
"name": "my-own-throttler",
"version": "1.0.0",
...
"dependencies": {
"@nestjs/config": "^3.1.1",
"@nestjs/core": "^9.0.0",
"@nestjs/graphql": "^11.0.6",
"@nestjs/throttler": "^5.0.0",
"rxjs": "^7.8.1"
}
}
In my host repo I'm using my throttler like this:
app.module:
@Module({
imports: [
...
GraphqlThrottlerModule,
],
providers: [
{
provide: APP_GUARD,
useClass: GqlThrottlerGuard,
},
],
})
export class AppModule {}
package.json:
{
"name": "my-host",
"version": "1.0.0",
...
"dependencies": {
"@nestjs/common": "^9.0.0",
"@nestjs/core": "^9.0.0",
"my-own-throttler": "1.0.0",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.2.0"
}
}
When i'm running my app, it shows me this error:
Nest can't resolve dependencies of the GqlThrottlerGuard (THROTTLER:MODULE_OPTIONS,
Symbol(ThrottlerStorage), ?).
Please make sure that the argument Reflector at index [2] is
available in the GraphqlThrottlerModule context.
When I put the same throttler code in the host repo, it works, but when I put it as a dependency in my package.json it does not work.
I suspected it might be a peer dependency issue, but when I tried to put the throttler as a peer dependency in the throttler package.json it still did not work.
I also tried to install @nestjs/[email protected] which uses nestjs 9, but it still didn't work.
In your
my-own-throttlerpackage, when publishing the@nestjs/packages should be set topeerDependencies, except for maybe@nestjs/throttlerif you aren't going to install that directly in your main project. The reason being is that eachnode_modules/@nestjs/commonandnode_modules/@nestjs/corehave their own class references to things likeReflectorandModuleRefwhich Nest will eventually being doing checks ofinjectedDependency instanceof Reflectorand if the wrongReflectoris pulled when instantiating the dependency, or during theinstanceofcheck, it fails, and Nest will no longer be able to resolve the injected depdnency and the application will fail to start.This is a side effect of JS Realms.
As
@nestjs/throttleralready sets@nestjs/commonand@nestjs/coreto peerDeps, you should be okay with keeping it as a dependency, but as a precaution, I'd probably just set it to apeerDependencyand be done with it. That way, if you need to make use of@ThrottleSkip()or the@Throttle()decorators you are able to without worry.Also, very important, make sure you are not installing this package locally (using an
npm linkornpm install ../packageas that will not properly respect the peer dependnecies. Either make a tarball usingnpm packand install the tar file directly, copy thepackage.jsonand thedisttonode_modules/<my-package>, or publish the package and install it with the usualnpm i <my-package>