If you've been keeping up I recently posted on how to create reusable data loaders with TypeScript. Now, we want to create a pattern where these are consumable inside of our GraphQL context. Since the GraphQL lifecycle is the same as the query lifecycle on our server, we can safely instatiate them in the context and they will be available with their caches for the entire lifecycle of our query. This is the best lifecycle to have for our dataloaders as instatiating them out of this context would effectively make them singletons and could accidentally expose sensitive information to unauthorized clients. If you want to read more on inversify and the Context Provider Pattern checkout my recent post on the subject.

Let's start by creating an interface for our DataLoader.

const IUserLoaderType = Symbol.for("IUserLoader");
interface IUserLoader extends DataLoader<number, User> { }

And we can update the example from the previous post to use this interface and add the injectable decorator.

@injectable()
class UserLoader implements IUserLoader extends DataLoader<number, User> {
    constructor(options?: DataLoader.Options<number, User>) {
        const batch = async (userIds: number) => {
            return User.findAll({ where: { id: userIds }});
        }
        super(batch, options);
    }
}

Before we can register our loader to our IoC container we need to configure the data loader library itself to be injectable. Inversify providers a couple methods for decorating a class that we don't own.

decorate(injectable(), DataLoader);
decorate(unmanaged(), DataLoader, 0);
decorate(unmanaged(), DataLoader, 1);

What this does is decorate DataLoader with the same injectable decorator we use on our classes and then we tell it that the two constructor parameters are going to be unmanaged by us.

Now that DataLoader has been configured for inversify we can bind our UserLoader.

container.bind<IUserLoader>(IUserLoaderType).to(UserLoader).inRequestScope();

Now we can use this DataLoader in any of our services registered in our ContextProvider and it will be available only during the lifecycle of the query.

Thanks for reading and happy coding!