royib / clean-architecture-nestJS

An in-depth implementation of Clean Architecture using NestJS and type-script
795 stars 192 forks source link

NestJs dependency at the use-case level #14

Closed Danswar closed 5 months ago

Danswar commented 10 months ago

Hey @royib, thanks for this repo, this is a very nice starting point for discussion.

I see that use-cases have a dependency on NestJs (like here for example). I expected to only find dependencies on the core entities on this layer and then another layer on top of use-case where framework dependencies starts to appear, but I think something is missing.

Could you expand a bit on the whys of your implementation please? I'd greatly appreciate it!

normyee commented 9 months ago

I think you can create a proxy class in the framework layer and call all the use-case methods from there. Also, I don't think we need to go so far as to follow clean architecture. I think it's okay to have a NestJS dependency if it's just for the decorators.

fiamon commented 8 months ago

agreed. @normyee @Danswar look at what Scott told about an other article, maybe it can change your mind

https://github.com/jonathanPretre/clean-architecture-nestjs/issues/4

alande-amorim commented 5 months ago

@Danswar just remove the @Injectable() decorator from the use-case class and add it to the dependency injection using the manual declaration:

function injectable<T extends Class<any>>(cls: T): Provider<T> {
  return { provide: cls, useClass: cls};
}

@Module({
  controllers: [UsersController],
  providers: [
    injectable(CreateUserUseCase),
    injectable(UpdateUserUseCase),
    ...
  ],
})
export class UsersModule {}
alande-amorim commented 5 months ago

agreed. @normyee @Danswar look at what Scott told about an other article, maybe it can change your mind

jonathanPretre/clean-architecture-nestjs#4

yes but also no. He's right about NestJS preferring (or rather facilitating) 'several smaller onions' vs 'big onion'. But he's right only on a scenario where you're coming from a small app (which is ok to use a MVCS'ish architecture). But what if your app is already big enough, what alternatives you've got? Sticking to Nest's suggested architecture?

stivendiaz commented 3 months ago

@alande-amorim, can you extend the solution to add the use case in the dependency injection using the manual declaration? I'm using a proxy this way:

@Module({
    imports: [MailParserServiceModule, WebpageServiceModule],
})
export class MailParserUseCaseModule {
    static GET_JSON_FILE_USECASES_PROXY = 'getJsonFileUsecasesProxy';

    static register(): DynamicModule {
        return {
            module: MailParserUseCaseModule,
            providers: [
                {
                    inject: [MailParserService, WebpageService],
                    provide:
                        MailParserUseCaseModule.GET_JSON_FILE_USECASES_PROXY,
                    useFactory: (
                        mailparserService: MailParserService,
                        webpageService: WebpageService,
                    ) =>
                        new UseCaseProxy(
                            new GetJsonFileUseCase(
                                mailparserService,
                                webpageService,
                            ),
                        ),
                },
            ],
            exports: [MailParserUseCaseModule.GET_JSON_FILE_USECASES_PROXY],
        };
    }
}

And I import it this way:

@Module({
    imports: [
        ConfigModule.forRoot({ envFilePath, isGlobal: true }),
        ExceptionsModule,
        MailParserUseCaseModule.register(),
    ],
    controllers: [MailParserController],
    providers: [],
})

How can I improve that injection?

Thanks a lot!