nmg49
nmg49

Reputation: 1386

Passing observable to subscriber.next and avoid nesting

I'm relatively new to rxjs and Observables. I'm trying to write a service method which returns an observable that when subscribed, will output the result of an HTTP request. However, before I can make the request, I have to ensure the proper authorization token is present (it won't always be there).

Here's the way I came up with to accomplish this task:

getDataFromHTTPCall (): Observable<any>  {
    return new Observable(subscriber => {
        if (this.authorizationToken == null) {
            subscriber.error("Authorization Token Required")
        } else {
            subscriber.next(
                from(
                    axios.get(`${this.baseUrl}/getData}`, { headers: {'Authorization': this.authorizationToken }})
                ).pipe(
                    map(result => result.data),
                    catchError( (err) => {
                        console.log(err)
                        return EMPTY
                    })
                )
            )
        }
    })
}

This technically works, but it has some major issues. Most notably, by passing an observable to an observable, it requires the caller of this function to subscribe twice. I've been reading that observables should never be nested like this, I can see why this wouldn't be desired.

I get the feeling there's a better way to accomplish what I'm trying to do here. Could someone advise on a better way to accomplish this kind of task using observables?

Upvotes: 0

Views: 235

Answers (2)

mbojko
mbojko

Reputation: 14679

The logic of the function sounds like "If you don't have stored credentials, throw error, otherwise return the axios call put through some pipe". Translated to RxJS, it could look like this:

  getDataFromHTTPCall(): Observable<any> {
    return this.authorizationToken == null
      ? throwError('Authorization Token Required')
      : from(
        axios.get(`${this.baseUrl}/getData}`, {
          headers: {Authorization: this.authorizationToken},
        }).pipe(/* etc */)
      );
  }

Upvotes: 2

Picci
Picci

Reputation: 17762

What about starting with emitting the value of this.authorizationToken and then using concatMap to call the http service or error if this.authorizationToken is null?

The code would look something like this

getDataFromHTTPCall() {
    return of(this.authorizationToken).pipe(
       concatMap(authToken => {
          if (authToken == null) {
            throw new Error("Authorization Token Required")
          }
          return from(axios.get(`${this.baseUrl}/getData}`, 
                                { headers: {'Authorization': authToken }})
                 ).pipe(
                    map(result => result.data),
                    catchError( (err) => {
                        console.log(err)
                        return EMPTY
                    })
                 )
       })
    )
}

Upvotes: 1

Related Questions