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/throttler@4.0.0
which uses nestjs 9, but it still didn't work.
In your my-own-throttler
package, when publishing the @nestjs/
packages should be set to peerDependencies
, except for maybe @nestjs/throttler
if you aren't going to install that directly in your main project. The reason being is that each node_modules/@nestjs/common
and node_modules/@nestjs/core
have their own class references to things like Reflector
and ModuleRef
which Nest will eventually being doing checks of injectedDependency instanceof Reflector
and if the wrong Reflector
is pulled when instantiating the dependency, or during the instanceof
check, 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/throttler
already sets @nestjs/common
and @nestjs/core
to peerDeps, you should be okay with keeping it as a dependency, but as a precaution, I'd probably just set it to a peerDependency
and 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 link
or npm install ../package
as that will not properly respect the peer dependnecies. Either make a tarball using npm pack
and install the tar file directly, copy the package.json
and the dist
to node_modules/<my-package>
, or publish the package and install it with the usual npm i <my-package>