Reputation: 636
I've a middleware to validate a user quota
and I need to inject the service that call the database into it to check this quota.
This is the middleware:
export class PointMaxStorageMiddleware implements NestMiddleware {
constructor(private readonly points: PointsService) {}
async use(req: Request, res: Response, next: NextFunction) {
const total = await this.points.count('user-id-test');
if (total >= LIMIT) throw new HttpException('error sample', 400);
// ...
}
}
The service class:
@Injectable()
export class PointsService {
private readonly logger = new Logger(PointsService.name);
constructor(
@InjectModel(Point.name)
private readonly collection: Model<PointDocument>,
) {}
async count(userId: string): Promise<number> {
return await this.collection.countDocuments({ userId: userId });
}
}
My service class has the Injectable
annotation and is being used on other parts of the project, but when I inject it into the middleware, I got the error:
Cannot read properties of undefined (reading 'count')
The count
method exist on the service.
I also tried to use like this:
constructor(
@Inject(PointsService) private readonly points: PointsService,
) {}
And got the erro:
Nest can't resolve dependencies of the PointsService (?). Please make sure that the argument PointModel at index [0] is available in the AppModule context. Potential solutions:
- If PointModel is a provider, is it part of the current AppModule?
- If PointModel is exported from a separate @Module, is that > module imported within AppModule? @Module({ imports: [ /* the Module containing PointModel */ ]}) Error: Nest can't resolve dependencies of the PointsService (?). Please make sure that the argument PointModel at index [0] is available in the AppModule context.
Also tried to add a new provider on the AppModule
class:
providers: [
{
provide: 'POINT_SERVICE',
useClass: PointsService,
},
]
constructor(
@Inject('POINT_SERVICE') private readonly points: PointsService,
) {}
And got the same error as above.
The injection is not being placed correctly, how can I inject a service into a middleware?
Upvotes: 0
Views: 5691
Reputation: 353
As Manuel Herrera
answer mentioned before that you must set the middleware up using the configure()
. But, remember that in NestJS if you want to share providers across the module, you have to import the source / the hosting module, not just provide the specified provider you want to use. In this case, if you want to share or provide the PointsService at the middleware module. It would be something like this:
@Module({
imports: [PointsModule], // this is the module where you provide the PointsService
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(PointMaxStorageMiddleware)
.forRoutes('myroute');
}
}
You can take a look at the dependency injection section inside the NestJS middleware documentation here.
Upvotes: 0
Reputation: 351
Nest cant resolve dependencies for an injectable that are outside its parent module
Remember NestMiddleware
is also an @injectable()
. This means first you define it, and then you must set it up using the configure()
method in a module (as the @module
decorator has no place for middleware) like so:
@Module({
providers: [PointsService],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(PointMaxStorageMiddleware)
.forRoutes('myroute');
}
}
note that PointsService
should be in the same module, be that through providers
or through imports
(if exported from another module)
check https://docs.nestjs.com/middleware for more information
Upvotes: 5
Reputation: 6695
You should have the @Injectable()
on classes that you want inject things into.
Since you want to inject PointsService
in the class PointMaxStorageMiddleware
, you need to annotate PointMaxStorageMiddleware
with that decorator.
Another approach would be:
@Inject(PointsService) private readonly points: PointsService
Upvotes: 2