In an Angular 9 service class I'm chaining a couple of HTTP calls using RxJS's concatMap, using the output of the first call as input the second:
getUserDetails(authorisationCode: string): Observable<UserInfo> {
this.getAuthorisationTokens(authorisationCode)
  .pipe(
    concatMap(authorisationTokens =>  this.getUserInfo(authorisationTokens.access_token)))
    .subscribe(
      (data: UserInfo) => {
        this.userInfo = data;
        console.log(JSON.stringify(this.userInfo));
        console.log(JSON.stringify(data));
      },
      (err: any) => console.log('Error getting user info details : ' + err),
      () => {
        console.log('Got user information: ' + this.userInfo);
      }
    );
return of(this.userInfo);
}
I want to return this.userInfo to a caller and my first naive idea was to wrap it in an Observable (return of(this.userInfo)) and call it like this:
export class LandingComponent implements OnInit {
  username: string;
  userFirstName: string;
  email: string;
  constructor(private route: ActivatedRoute, private userService: UserDataService) {
    this.authorisationCode = route.snapshot.queryParamMap.get('code');
    console.log('Code was ' + this.authorisationCode);
  }
  ngOnInit(): void {
    this.userService.getUserDetails(this.authorisationCode)
      .subscribe((data: UserInfo) => {
        this.userFirstName = data.given_name;
        this.username = data.preferred_username;
        this.email = data.email;
        console.log('Got: ' + this.userFirstName + ', ' + this.username + ', ' + this.email);
      });
  }
}
I can see from the browser console that the calls to my services are succeeding and populating my object this.userInfo, but only after I've tried to use it and got an undefined error:
Code was 2ffa40f9-5e71-4f29-8ddd-318e8d0b99bc
main-es2015.8df8d853b157ca70b40a.js:1 Getting authorisation tokens in exchange for authorisation code 2ffa40f9-5e71-4f29-8ddd-318e8d0b99bc
main-es2015.8df8d853b157ca70b40a.js:1 Header: [object Object]
main-es2015.8df8d853b157ca70b40a.js:1 Body: grant_type=authorization_code&redirect_uri=https://xxx/landing/&client_id=xxx&code=2ffa40f9-5e71-4f29-8ddd-318e8d0b99bc&client_secret=xxx
main-es2015.8df8d853b157ca70b40a.js:1 TOKEN endpoint: https://xxx.amazoncognito.com/oauth2/token
TOKEN endpoint: https://xxx.amazoncognito.com/oauth2/token
main-es2015.8df8d853b157ca70b40a.js:1 ERROR TypeError: Cannot read property 'given_name' of undefined
    ...
USERINFO endpoint https://xxx.amazoncognito.com/oauth2/userInfo
main-es2015.8df8d853b157ca70b40a.js:1 USERINFO endpoint https://xxx.amazoncognito.com/oauth2/userInfo
main-es2015.8df8d853b157ca70b40a.js:1 {"sub":"4bfd88a4-5439-4ad6-a399-71b02034dfa1","email_verified":"true","given_name":"Craig","family_name":"Caulfield","email":"craig.caulfield@xxx.com","username":"4bfd88a4-5439-4ad6-a399-xxx"}
main-es2015.8df8d853b157ca70b40a.js:1 Got user information: [object Object]
I've tried to apply the following questions, but I can't find a way to apply them to my case:
- Angular: What's the correct way to return Observable?
- What is the proper way to return from within an angular subscription?
So, my async thinking is wrong. Is there something obvious that I haven't done?
 
     
    