#How to deeply understand NestJs DI once and for all

31 messages · Page 1 of 1 (latest)

real basin
#

Hi everyone,

Lastly I tried to migrate TypeOrm into 0.3.12 version, and had to fight hard to inject the right custom repositories.

But in a general manner, I find that I struggle mostly with the NestJs DI system that kinda act as a blackbox with unexpressive errors.

I had to use useClass, then useExisting then back to useClass. Before I didn't need to export providers, now I have too. All of this triggered by a dependencies migration, it doesn't feel right (but at least I fixed my my tests)

What ressources should I read to get the right mental framework when working with it?

topaz garnet
#

So, I guess the question is what about it is unclear to you?

latent gorge
#

I didn’t worked with any DI system before using nestjs, just raw nodejs and typescript stuff. Still, I found those error messages pretty clear once I managed to understand what they mean in general
Basically, I’ve read the docs a couple times, and almost all the articles from https://dev.to/nestjs

We could still try to improve something, as we’ve done already. To do so, we need to understand exactly what is unclear to you

Can you provide us some concrete example that you’ve struggled with?

DEV Community

nestjs node.js typescript javascript

random fractal
real basin
#

Thanks @random fractal it's always a good refresher to read some Martin Fowler 👌🏻

I believe I have a good theoretical understanding of the DI pattern, I have used it before.

It's really more about the NestJs DI system that is getting me confused.

I had to use useClass, then useExisting then back to useClass. Before I didn't need to export providers, now I have too.

It's really more about those NestJs implementation details that I can't get right.

For example, I had an implementation that used useExiting but no export. And after many trial and errors, I now needs to use useClass and export, and I don't why I can't keep my former one.

The fact that I can't explained those details clearly reveals that it's kinda a black box to me, and I am seeking a more details explanation, such that I have no doubt when using one technique or another.

topaz garnet
#

For example, I had an implementation that used useExiting but no export. And after many trial and errors, I now needs to use useClass and export, and I don't why I can't keep my former one.
Could you show us how you had this set up/what the current set up is/etc so that we might be able to help explain what is happening

latent gorge
real basin
#

Of course. My apologies for replying late, I'm running out of time nowadays.

So, I lost a bit of familiarity with NestJs lastly because I have been hired as a frontend and use it only for side projects.

Therefore, I tried to analyze what I tried re-reading my own Github.

Here we go:

So I am opening my side project again, and decide that I want to update all packages using yarn upgrade --interactive. Among all those packages, TypeOrm is breaking!

I decide, in a TDD fashion, to be driven by my tests. I focus first on integration tests such as:

https://github.com/amehmeto/corpo-sano/blob/migrate/typeorm/back/src/athlete/repositories/typeorm-athlete.repository.inte.ts

For example:

  it('should find an athlete by id', async () => {
    const expectedAthlete = new Athlete({
      ...athleteFixture,
      ...expectedBaseEntity,
      biometrics: new Biometrics(biometricsFixture),
      dailyTasks: dailyTaskFixtures.map(
        (fixture) =>
          new DailyTask({
            ...fixture,
            ...expectedBaseEntity,
          }),
      ),
      programs: programFixtures.map(
        (fixture) =>
          new Program({
            ...fixture,
            ...expectedBaseEntity,
          }),
      ),
    })

    const retrievedAthlete = await athleteRepository.findById(athleteFixture.id)

    expect(retrievedAthlete).toStrictEqual(expectedAthlete)
  })
GitHub

Contribute to amehmeto/corpo-sano development by creating an account on GitHub.

#

So after some research and guidance, I understand I need to do those changes highlighted by this github

#

As a consequences, I change my integration tests imports as such

#

Like so for every repositories, I am fixing my integrations tests fine, I'm happy

#

I now change the imports likewise in the athlete module

#

As far as I understand, if my imports are done correctly on my modules, I shouldn't need to change anything on my app.module.ts that will automatically dig on the domain modules. At least it worked like this before I thought. But I just can't make it work.

#

I used to use useExisting

#

Oh gosh, I might get the issue here. getRepositoryToken might not be relevant now

#

I'll finish this thread either way.

What I'm guessing, useExisting is trying to use an already used instance from somewhere, when useClass might use a new instance everywhere it called. But I am just guessing.

I just realize now that getRepositoryToken might be linked to the now obsolete @EntityRepository, maybe I should switch back to useClass

#

So because I can't make it work, I am calling a friend for help, that advice me to another approach for the TypeOrm migration

#

And now he insists that I need to import the entity, use useClass and export the TypeOrmRepository to make it now to the app

#

So that's why I want to read more about those quirks because clearly the mechanics of the DI system is cloudy in my mind

#

Sorry for the long thread, but at least it's exhaustive. 🙏🏻

#

Actually now I am wondering why it use to work with useExisiting but not anymore. I am wondering if I really have to give up this way of providing a provider. If my friends approach is the right one. What's the difference, etc...

topaz garnet
#

Okay, from a quick glance, a lot of the confusion will come from how the Typeorm module used to work vs how it works now because of the Typeorm 0.3.0 changes.

In the past, the custom repository was a class that had it's own decorator and everything. As you've noticed that's no longer the case so the old way doesn't work the same way as it does now.

Personally, if I were to make a custom repository class now I'd create a dedicated service that injects the Typeorm repository, exposes it, and provides it's own helper methods rather than work with typeorms extension approach

real basin
#

Any code exemples ?

topaz garnet
#

Oh which part in particular?

real basin
#

"Personally, if I were to make a custom repository class now I'd create a dedicated service that injects the Typeorm repository, exposes it, and provides it's own helper methods rather than work with typeorms extension approach"

#

I believe I need to re-read this carefully : https://docs.nestjs.com/fundamentals/custom-providers#export-custom-provider

I am confused by all those way of injecting custom providers

#

And by the apparent necessity to export and import eveything

topaz garnet
# real basin "Personally, if I were to make a custom repository class now I'd create a dedica...

Ah, okay, so for this you'll keep the imports: [TypeOrmModule.forFeature([X])] and you'll create a repository class that goes in the providers and exports like [XRepository]. Then the class will look something like this:

@Injectable()
export class XRepository {
  constructor (@InjectRepository(X) readonly repo: Repository<X>) {}

  async method1(params) {
    return this.repo.baseMethod(modifiyParamsByMethod(params))
  }
...
}
real basin
#

Also a question persist in my mind. If my integration test pass (meaning they can find those repositories) . Why can't the root app module find them? 🤔