Reputation: 9443
I have a nestjs graphql application which uses DataLoader. It works fine for queries and mutations, but it does not work for subscriptions. This is how configuration is defined in app.module:
@Module({
imports: [
...
GraphQLModule.forRootAsync({
driver: ApolloDriver,
imports: [TasksModule],
inject: [TasksService],
useFactory: (tasksService: TasksService) => ({
playground: true,
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
context: () => createTaskLoaders(tasksService),
subscriptions: {
'graphql-ws': true,
'subscriptions-transport-ws': true
}
})
})
]
})
export class AppModule {}
This is how context is used in the resolver:
@ResolveField()
async fieldSet(@Parent() task: Task, @Context() context) {
console.log('context', Object.keys(context)) // The output is empty when it runs for subscription
return context.someCustomLoader.load(task.id)
}
It does not matter what createTaskLoaders
and someCustomLoader
are - they are just custom functions. The issue is that they are not passed to the context when it's used from inside a subscription. I guess some additional configuration is needed for subscriptions case, but I can not find any working nestjs dataloader + subscriptions example as well as documentation about context for subscriptions.
Upvotes: 1
Views: 1139
Reputation: 685
I took a slightly alternative solution:
Inside a Resolver you can use the resolve
callback and access the context there
@Subscription((returns) => MyEvent, {
resolve(payload, _args, context, info) {
const myEvent = payload[info.fieldName];
context['myDataLoader'].clear(myEvent.referenceKey);
return myEvent;
},
})
entityUpdated(): AsyncIterator<unknown, any, undefined> {
return this.pubSub.asyncIterator('entityUpdated');
}
MyEvent
is my own class, so this could something different for you
More described here: https://docs.nestjs.com/graphql/subscriptions#mutating-subscription-payloads
Upvotes: 2
Reputation: 865
You have to pass the loaders manually in subscriptions using the onConnect
subscriptions: {
'graphql-ws': {
path: '/graphql',
onConnect: (context: Context) => {
const { connectionParams, extra } = context;
extra.loaders = createTaskLoaders(tasksService);
},
},
'subscriptions-transport-ws': {
path: '/graphql',
onConnect: (connectionParams) => {
return {
loaders: createTaskLoaders(tasksService),
};
},
},
},
Something like this should work
Upvotes: 2