Búsqueda de sitios web

angular - proporcionar API o versión simulada basada en una bandera de tiempo de ejecución


Me gustaría proporcionar una implementación simulada o real de una interfaz de API basada en un indicador de tiempo de ejecución. Aquí está mi enfoque actual:

providers:[{
  provide: MyApi,
  useFactory: () => {
     return env.useSpoofData ? mockMyApi : MyApi
  }
}]

He definido mockMyApi como:

export const mockMyApi: MyApi = {
  get(): Observable<MyResponse> {
    const resp: MyResponse = {items};
    return observableOf(resp);
  },
};

La versión simulada de esto funciona, pero la versión real, cuando se proporciona de esta manera, no funciona. (sin embargo, la versión real funciona si no hago esta sobrescritura del proveedor en absoluto)

He intentado dos maneras de resolver el símbolo para la implementación "real".

Uno :

provide: MyApi,
deps: [MyApi],
useFactory: (real: MyApi) => env.spoof ? mockMyApi : real;

Falla. Dependencia cíclica en tiempo de compilación.

Dos :

provide: MyApi,
deps: [Injector],
useFactory: (inj: Injector) => env.spoof ? mockMyApi : inj.get(MyApi);

Falla. Desbordamiento de pila en tiempo de ejecución.

¿Cuál es la manera correcta de instanciar o proporcionar una clase al devolverla desde un useFactory? O, ¿hay una manera más sencilla de hacer la sobreescritura de proveedores?

Respuesta #1

Proporcionas una fábrica, por lo que no puedes simplemente pasar el token de inyección como resultado de la fábrica. mockMyApi es una constante mientras que MyApi es una clase. Por lo tanto, necesitas crear un objeto de esa clase. Esto es para lo que normalmente se usan las fábricas. Usa deps para pasar dependencias, por ejemplo, HttpClient:

providers:[{
  provide: MyApi,
  useFactory: (http: HttpClient) => {
     return env.useSpoofData ? mockMyApi : new MyApi(/* args, e.g. http */)
  },
  deps: [HttpClient]
}]

Respuesta #2

La mejor solución que puedo encontrar es crear una nueva API «envuelta». Luego, cambiar todos los consumidores para que apunten a la nueva MyApiWrapped. En tu nueva implementación:

provide: MyApiWrapped,
deps: [Injector],
useFactory: (inj: Injector) => env.spoof ? mockMyApi : inj.get(MyApi);

De esta manera, puedes proporcionar cualquiera de las implementaciones sin causar una dependencia circular. Además, el uso de Injector aquí significa que estás permitiendo que Angular gestione la instancia singleton en caché de tu servicio y la configure con las dependencias correctas.