nestjs global pubsub instance and dependency injection
Asked Answered
C

2

6

I followed the Nestjs DOCS regarding pubsub/subsciprtions:

According to the examples, pubsub is initialized at the top of a given resolver with:

const pubSub = new PubSub();

later the docs say:

"We used a local PubSub instance here. Instead, we should define PubSub as a provider, inject it through the constructor (using @Inject() decorator), and reuse it among the whole application"

{
  provide: 'PUB_SUB',
  useValue: new PubSub(),
}

where does this go though?
I.e. what's the syntax/approach for how to provide this in my main app.module so it's available in all other modules?

if i try to provide this as a dependency in a different module i'm getting dependency resolution issues. app.module

  providers: [
    AppService,
    {
      provide: APP_FILTER,
      useClass: AllExceptionsFilter,
    },
    {
      provide: 'PUB_SUB',
      useValue: new PubSub(),
    },

some-resolver.js

  constructor(
    @Inject('PUB_SUB')
    private pubSub: PubSub,

gives: Nest can't resolve dependencies of the MyResolver ( MyResolver is provided by MyModule

I can't import appmodule into MyModule or i'll create a circular depenency.

Do i define a new module which just provides a pub_sub instance?

Chordophone answered 29/11, 2019 at 12:3 Comment(0)
P
12

If you're looking for it to easily be available to all your other modules, I would suggest creating a PubSubModule that provides your PubSub and exports it if you want to have to import the module, or just has the module marked as @Global() so the PubSub can be injected anywhere

Exports Method

@Module({
  providers: [
    {
      provide: 'PUB_SUB',
      useClass: PubSub,
      // useValue: new PubSub(),
      // useFactory: () => {
      //  return new PubSub();
      // }
    }
  ],
  exports: ['PUB_SUB'],
})
export class PubSubModule {}

Global Method

@Global()
@Module({
  providers: [
    {
      provide: 'PUB_SUB',
      useClass: PubSub,
      // useValue: new PubSub(),
      // useFactory: () => {
      //  return new PubSub();
      // }
    }
  ],
})
export class PubSubModule {}
Psychosis answered 29/11, 2019 at 16:58 Comment(2)
thanks a lot, this is indeed where i landed. what is the disadvantage of using the global decorator? other module instantiations done in appmodule, like typeorm, graphql, etc don't seem to follow this pattern. And again in the docs, nest team does not mention using this for say, custom logger. Still hazy on how some features are 'magically' available after being configured in main app.module. So far this is the only instance where i'm using the 'global' decoratorChordophone
I don't really see drawbacks to it, other than like you said, it "magically" being available. I actually worked with a contributor recently to figure out a way around using Global but still only working with configurations once. I like to not use @global() just because it makes me think about what is really available in the current scope of thingsPsychosis
E
0

Using with async/await init pubSub:

// pubSub.module.ts
@Module({
  providers: [
    {
      provide: PubSub,
      // if you need init with async/await
      useFactory: async () => {
        return await getPubSub();
      },
    },
  ],
  exports: [PubSub],
})
export class PubSubModule {}

// test.module.ts
@Module({
  imports: [PubSubModule],
  providers: [TestService]
})
export class TestModule {}

// test.service.ts
export class TestService {
  constructor(private pubSub: PubSub) {}

  @Subscription(() => any)
  testAdded() {
    return this.pubSub.asyncIterator('TEST_ADDED');
  }
}

Eanore answered 15/9, 2022 at 10:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.