I'd like to provide either a mock or real implementation of an API interface based on a runtime flag. Here's my current approach:
providers:[{
provide: MyApi,
useFactory: () => {
return env.useSpoofData ? mockMyApi : MyApi
}
}]
I have defined mockMyApi as:
export const mockMyApi: MyApi = {
get(): Observable<MyResponse> {
const resp: MyResponse = {items};
return observableOf(resp);
},
};
The mock version of this works, but the real version, when provided this way, does not work. (the real version works if I don't do this provider overriding at all, however)
I have tried two ways to resolve the symbol for the "real" implementation.
One:
provide: MyApi,
deps: [MyApi],
useFactory: (real: MyApi) => env.spoof ? mockMyApi : real;
Fails. Cyclic dependency at build time.
Two:
provide: MyApi,
deps: [Injector],
useFactory: (inj: Injector) => env.spoof ? mockMyApi : inj.get(MyApi);
Fails. stack overflow at run time.
What's the correct way to instantiate or provide a class when returning it from a useFactory? Or, is there a simpler way to do provider overriding?
You provide a factory, so you cannot simply pass the injection token as a factory result. mockMyApi is a constant while MyApi is a class. So, you need to create an object of that class. This is what factories are normally used for. Use deps to pass dependencies, e.g. HttpClient:
providers:[{
provide: MyApi,
useFactory: (http: HttpClient) => {
return env.useSpoofData ? mockMyApi : new MyApi(/* args, e.g. http */)
},
deps: [HttpClient]
}]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With