paint-brush
NestJS vs. Ditsmod: the features of providersby@mostyk
151 reads

NestJS vs. Ditsmod: the features of providers

by Kostia TretiakJuly 31st, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

I decided to write this article while browsing NestJS issues, in particular A guard with dependencies can't be injected into another module. Its author wonders why NestJS cannot resolve the dependency for AuthGuard because this dependency is imported into the module where the guard is declared.
featured image - NestJS vs. Ditsmod: the features of providers
Kostia Tretiak HackerNoon profile picture

Interceptors, guards, pipes, and exception filters are sometimes referred to as "enhancers" in the NestJS documentation. Although they are all declared with the @Injectable() decorator and can use Dependency Injection, they are not providers. Therefore, they cannot be exported from the module like normal providers.


This article uses NestJS v10.1 and Ditsmod v2.38 for comparison. I am the author of Ditsmod.


I decided to write this article while browsing NestJS issues, in particular A guard with dependencies can't be injected into another module. Its author wonders why NestJS cannot resolve the dependency for AuthGuard because this dependency is imported into the module where the guard is declared.


And the creator of NestJS wrote the following answer:


Enhancers can’t be injected to other providers. Hence, they are not providers. Likewise, enhancers can be tied & injected to the method evaluation context, but you can’t bind providers this way. There’s no reason to change this, especially if you start thinking about enhancers scoped per host (module in which they exist). Adding them to the providers array explicitly creates an unnecessary redundancy and confusion (since enhancers don’t act equally to providers).


So, according to Kamil, adding interceptors, guards, pipes and exception filters to the list of providers will confuse NestJS users. As a result of these restrictions, NestJS applications must export all dependencies for guards from the module, even if those dependencies are not directly used outside the module in which the guards are declared. This restriction essentially breaks module encapsulation.


In Ditsmod, the guards, interceptors, and controller error handlers (analogous to exception filters in NestJS) are normal providers that are passed to the injector at the request level. In next code demonstrates the centralized addition of a guard on OtherModule:


import { featureModule } from '@ditsmod/core';

import { OtherModule } from '../other/other.module';
import { AuthModule } from '../auth/auth.module';
import { AuthGuard } from '../auth/auth.guard';

@featureModule({
  imports: [
    AuthModule,
    { path: 'some-path', module: OtherModule, guards: [AuthGuard] }
  ]
})
export class SomeModule {}


In this example, the AuthModule exports the AuthGuard so that the current module can use this guard as a regular provider.


Also published here.