4

In my SPA, I'm using the APP_INITIALIZER token, which is supposed to perform the following in the given sequence. 1) Load the config file relevant to the environment (DEV, QA, PROD). 2) Use the API URL from the config file to make the HTTP request for the authentication token 3) Use the API URL from the config file and append the token to the HTTP request (this happens within the token interceptor) to load some other config data)

Earlier I had 2 and 3 implemented with the URL hard-coded, and then everything worked fine. When I moved the API Urls to the config and tried loading them from the config file, the token endpoint is executed before the config file request is resolved, therefore the url becomes undefined.

See the code below:

app.module.ts

export function initializeData(appConfig: AppConfig, authService: AuthService, appService: AppService, globalService: GlobalService) {
  return () => {
    try {
      return Promise.all([appConfig.load(), authService.authenticateClient(), appService.getClientConfig()]).then(() => {
        console.log('success')
        return Promise.resolve();
      }, (err) => {
        alert(err.error.error_description);
        return Promise.reject(err);
      });
    } catch (e) {
      alert(e.message);
      console.log(e);
    }

  }
}

@NgModule({
.............
.............
providers: [
    AppConfig,
    AuthService,
    {
      provide: APP_INITIALIZER,
      useFactory: initializeData,
      deps: [AppConfig, AuthService, TranslateService, AppService, GlobalService],
      multi: true
    },
    AppService
]
});

app.config.ts:

@Injectable()
export class AppConfig {
  static settings: IAppConfig;
  constructor(private http: HttpClient) { }
  load() {
    const jsonFile = `assets/config/config.${environment.name}.json`;

    return new Promise((resolve, reject) => {
      this.http.get(jsonFile).pipe(map((res: IAppConfig) => {
        AppConfig.settings = <IAppConfig>res;
        return AppConfig.settings;
      })).subscribe(() => {
        resolve();
        })
    }).catch ((response: any) => {
        console.log(`Could not load file '${jsonFile}': ${JSON.stringify(response)}`);
      });
  }
}

auth.service.ts (token endpoint):

authenticateClient(){
    let body = new HttpParams()
      .set('client_id', AppConfig.settings.apiServer.client_id)
      .set('grant_type', AppConfig.settings.apiServer.grant_type)
      .set('scope', AppConfig.settings.apiServer.scope);

    const httpOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'application/x-www-form-urlencoded'
      })
    };

    let authGatewayUrl: string = AppConfig.settings.apiServer.tokenUrl + window.location.search;

    return  this.http.post<any>(authGatewayUrl, body, httpOptions).toPromise().then(
        data => {
          this.token.next(data); 
          return this.token;
        },
        error => {
          return Promise.reject(error);
        }
      );  
  }

Now, when I add breakpoints in app.config.ts and auth.service.ts, in the latter file, AppConfig.Settings.apiServer.tokenUrl get hit before the app config file is resolved. Hence it becomes undefined.

How can I resolve this? I know I should be using switchmap, but I'm not sure how to approach it.

3
  • 2
    appConfig.load().then(()=>Promise.all[authService.authenticateClient(), appService.getClientConfig()].then....)? Commented Dec 6, 2018 at 18:07
  • Thanks. I shouldn't have missed that. Please add a reply so that I can mark it as answer. Commented Dec 7, 2018 at 9:35
  • reply added as you said :) Commented Dec 7, 2018 at 13:52

1 Answer 1

3

Perhaps you can control the sequence in .then callback:

appConfig.load()
  .then(()=>
     Promise.all[
       authService.authenticateClient(),
       appService.getClientConfig()
     ]
     .then....)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.