Home > database >  Typescript Observables and Promises
Typescript Observables and Promises

Time:12-13

I am attempting to implement OIDC in an Angular project. Eveything was going great until I tried to implement an HPPT interceptor to set the Authorization header. I have a method on the auth service that returns the token as a promise: `

getAccessToken()
  {
    return this._userManager.getUser().then(user =>
      {
        if(!!user && !user.expired)
        {
          return user.access_token
        }
        else
        {
          return null
        }
      })
  }

Here is my intercept method

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> 
  {
    if(req.url.startsWith(Constants.avlApiRootUrl))
    {
      return from(this._authService.getAccessToken().then(token =>{
        const headers = new HttpHeaders().set('Authorization', `Bearer ${ token }`)
        const authReq = req.clone({headers})
        return next.handle(authReq)
      }))
   }
    else
    {
      return next.handle(req)
    }
  }

` When I try to call this from the intercept class on the HTTPInterceptor I get an error: Type 'Promise<Observable>' is missing the following properties from type 'Observable': source, operator, lift, subscribe, and 3 more.ts(2740)

I understand that I am returning the wrong type but everything I can find about this says to use a toPromise method that has been depreciated. Can anyone tell me how to do this, I'm out of ideas. More than having someone write my code for me (which I would take at this point) I'd really like to understand this so if you can point to a write up or documentation That would be awesome.

CodePudding user response:

Since you're returning next.hande() within your promise, it's returning Observable<Promise<Observable<T>>>. You need to return plain Observable<T>:

To accomplish this you can make modifications to your observable stream using .pipe() with some operators. We can start with your promise wrapped in from(), like you had, then map the result into a new headers object, then into an auth reqeust object, then finally into a call to next.handle():

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if(req.url.startsWith(Constants.avlApiRootUrl)) {
        return from(this._authService.getAccessToken()).pipe(
            map(token => new HttpHeaders().set('Authorization', `Bearer ${ token }`)),
            map(headers => req.clone({headers})),
            mergeMap(authReq => next.handle(authReq))
        );
   }

   return next.handle(req)
}

The reason for the mergeMap at the end is because we want to emit the emissions from next.handle(), not the next.handle() observable itself.

  • Related