Dependency Injection friendly adaptation of graphql/dataloader for NestJS.
This package internally uses
AsyncLocalStorage
to provide a clean cache map for each dataloader in each request, but it may have a slight negative impact on the performance.
npm i @nestjs-devkit/dataloader
To define a dataloader, we simply extend the abstract DataLoader
and implement the resolve()
method.
import { DataLoader } from "@nestjs-devkit/dataloader";
// ... more imports
@Injectable()
export class UserIdLoader extends DataLoader<number, User> {
constructor(@InjectRepository(User) private repo: EntityRepository<User>) {}
protected async resolve(keys: number[]): Promise<User[]> {
return this.repo.find({ id: { $in: keys } });
}
}
Before using the dataloaders, we need to firstly provide these dataloaders.
@Module({
providers: [UserIdLoader],
exports: [UserIdLoader],
})
export class UsersModule {}
Besides, the DataLoaderModule
is also required for them to work.
@Module({
imports: [DataLoaderModule.forRoot()],
})
export class AppModule {}
Now we can use the dataloaders simply by injecting them into your resolvers.
@Resolver(() => Book)
export class BooksResolver {
constructor(private userIdLoader: UserIdLoader) {}
@ResolveField()
async owner(@Parent() book: Book) {
return this.userIdLoader.load(book.owner.id);
}
}
Remember to import the module where the dataloader is defined.
@Module({
imports: [forwardRef(() => UsersModule)],
})
export class BooksModule {}
There is a DataLoaderContext
used to provide clean cache maps for dataloaders in each request, which need to be applied by a middleware.
By default, a built-in middleware will be automatically applied to apply the context for Express. You can disable it and apply it on your own for other platforms.
@Module({
imports: [DataLoaderModule.forRoot({ middleware: false })],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer): void {
// Express (Default)
consumer.apply(DataLoaderContextMiddleware).forRoutes("*");
// Fastify
consumer.apply(DataLoaderContextMiddleware).forRoutes("(*)");
}
}
Pull requests are always welcome, but please open an issue firstly before major changes. ;]