I have the next provider configuration
{
provide: APP_INITIALIZER,
useFactory: initializeKeycloak,
multi: true,
deps: [KeycloakService],
},
How to make an HTTP call from useFactory function (initializeKeycloak)?
function initializeKeycloak(keycloak: KeycloakService) {
return () =>
keycloak.init({
config: {
url: environment.keycloak.url,
realm: environment.keycloak.realm,
clientId: environment.keycloak.clientId
}
});
}
I want to get this value from the assets folder
environment.keycloak.url
There are 2 things you need to know here:
asyncFactory
function you can return a promise that indicates when the intialization is done.HttpClient
to the dependencies of the APP_INITIALIZER
. Note that you must add the HttpClientModule
to the imports of your AppModule
so that it is available for injection.Working example for RxJS 6:
const initializeKeycloak = (
keycloakService: KeycloakService,
httpClient: HttpClient // The httpClient is available here because you added it to the deps of the APP_INITIALIZER
) => {
return () =>
httpClient
.get(url)
.pipe(
tap((environment: any) => {
keycloakService.init({
config: {
url: environment.keycloak.url,
realm: environment.keycloak.realm,
clientId: environment.keycloak.clientId
}
});
})
)
.toPromise(); // Return the promise to indicate the initialization is done.
};
@NgModule({
imports: [BrowserModule, FormsModule, HttpClientModule],
declarations: [AppComponent, HelloComponent],
bootstrap: [AppComponent],
providers: [
{
provide: APP_INITIALIZER,
useFactory: initializeKeycloak,
multi: true,
deps: [KeycloakService, HttpClient] // Add the HttpClient here.
},
KeycloakService
]
})
export class AppModule {}
Working example for RxJS 7+ (toPromise will become deprecated, you have to use lastValueFrom):
import { lastValueFrom } from "rxjs";
...
const initializeKeycloak = (
keycloakService: KeycloakService,
httpClient: HttpClient
) => {
return () => {
const request$ = httpClient.get(url).pipe(
tap((environment: any) => {
keycloakService.init({
config: {
url: environment.keycloak.url,
realm: environment.keycloak.realm,
clientId: environment.keycloak.clientId
}
});
})
);
return lastValueFrom(request$);
};
};
On a side note:
While it is possible to retrieve the environment information on startup, this has the drawback that the app won't load at all if the request fails. It might be worth it here to add a retry mechanism.
There are also ways to inject environment variables at build-time, I provided information on that topic in this answer.