Describe the issue
I would like to inject a few dependencies into a resolver, but I do not want to use a dependency injection framework.
Are you able to make a PR that fix this?
If necessary I can work on it, but I assume this is a documentation gap.
Additional context
If I just need to inject one or two objects into a resolver, then I shouldn't need to import an entire DI framework to solve this. If type-graphql expects certain DI APIs, it would be nice to see a guide for how to mock a container and pass this into buildSchema
It is possible to pass dependencies to resolvers without using typedi.
import Container from 'typedi'
const dep1 = new Dep1()
const dep2 = new Dep2()
const myResolver = new MyResolver(dep1, dep2);
Container.set(MyResolver, myResolver);
const schema = await buildSchema({
[myResolver, /* other resolvers */],
Container,
...
})
But I guess there is no way around using typedi for injecting the resolvers into buildSchema() but using a Container.
Using dependency injection without container is not a good idea as you're asking yourself into maintenance problems.
However, TypeGraphQL has no requirements about the used container - it's not coupled with typedi, inversify-js or other libs. All you have to provide is an object with a get method that receive the resolver class and should return an instance of the class.
So in your case, it might look like this:
const dep1 = new Dep1()
const dep2 = new Dep2()
const myResolver = new MyResolver(dep1, dep2);
const MyContainer = {
get(ResolverClass) {
if (ResolverClass === MyResolver) {
return myResolver;
}
return new ResolverClass();
}
};
const schema = await buildSchema({
resolvers: [MyResolver, OtherResolver],
container: MyContainer,
});
So it will use the provided instance for selected resolver, otherwise it will create a new instance of the class. You can enhance the example with some caching like in DefaultContainer.
Thanks! This answers the question I had.
Is there any reason I can't just provide the dependency via a function arg? It feels weird I am forced to involve this framework
via a function arg
What do you mean?
If you want to use dependency injection pattern (provide dependencies into constructor), just use a DI container like the simple and easy to use TypeDI. There's no sense to resolve the deps chain manually, it's in a long term a maintenance hell.
via a function arg
What do you mean?
If you want to use dependency injection pattern (provide dependencies into constructor), just use a DI container like the simple and easy to use TypeDI. There's no sense to resolve the deps chain manually, it's in a long term a maintenance hell.
Something like:
const schema = await buildSchema({
resolvers: [new MyResolver(new Dep1(), new Dep2()), new OtherResolver()],
});
Is there any reason I can't just provide the dependency via a function arg?
So I will reverse the question - is there any reason you can just use DI container to resolve the dependencies? 馃槈
resolvers: [new MyResolver(new Dep1(), new Dep2()), new OtherResolver()],
This syntax would really complicate the default container that is supposed to be simple:
https://github.com/MichalLytek/type-graphql/blob/877f197dfa8d4d2d7890a38dfc0bf1a548febcc8/src/utils/container.ts#L18-L30
I would have to reinvent the wheel and provide a functionality that is equal to Container.set(MyResolver, new MyResolver(new Dep1(), new Dep2()) - I need to detect if the provided resolver value is function (class) or object (class instance), then read the constructor to have a reference to the class and then register it in instances of the default container.
And it's against design goal - default container is just a "placeholder" if you don't need dependency injection, and if you need, you should use a container library or your simple custom solution that I've showed.
Most helpful comment
Is there any reason I can't just provide the dependency via a function arg? It feels weird I am forced to involve this framework