4

I'm having trouble figuring out how to use the result of an Http request to make another Http request.

I have a Service that requests and receives JSON Web Tokens from a backend API that looks like:

@Injectable()
export class JwtAuthorizationService {

  constructor(private http: Http) {}

  public requestToken(): Observable<string> {
    // Set dummy credentials.
    let body = this.setBody();
    let headers = this.setHeaders();
    let token = this.http.post(tokenUrl, body, { headers: headers })
      .map(this.extractData)
      .catch(this.handleError);

    // Return the Observable
    return token;
  }

  private extractData(res: Response): string {
    let body = res.text();
    return body || "";
  }

How can I now use the result of the requestToken() (an Observable) to make an another API call, authenticated with the JWT, and get the result back from that? Or maybe more simply, what do you do when one Http call depends on the result of another?

cartant
  • 57,105
  • 17
  • 163
  • 197
cbierman
  • 400
  • 5
  • 15

2 Answers2

5

You could use the flatMap operator to do that:

this.authorizationService.requestToken().flatMap(token => {
  var headers = new Headers();
  headers.append('Authorization', `Bearer ${token}`);
  return this.http.get('...', { headers }).map(res => res.json());
});

What you could also do is to make this transparent by extending the HTTP class. In it, you could check the token validity and if it's expired, call the requestToken method.

See this question for more details:

Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • I tried using `flatMap()`, but kept getting `Property 'flatMap' does not exist on type 'Observable'.` on compile. Is this because my `requestToken()` method returns the token as a string on success? – cbierman Jun 16 '16 at 14:18
  • In fact, it's because the flatMap operator i's an alias to the mergeMap one ;-) You need import it this way: import 'rxjs/add/operator/mergeMap'; – Thierry Templier Jun 16 '16 at 17:04
  • See this question: http://stackoverflow.com/questions/34515173/angular-2-http-get-with-typescript-error-http-get-map-is-not-a-function-in/34515276#34515276 – Thierry Templier Jun 16 '16 at 17:08
  • The difference between flatMap and switchMap is that the first one doesn't the previous in-progress observable / request. In your case it's enough. SwitchMap is particularly useful for autocompletion (for example) – Thierry Templier Jun 16 '16 at 17:10
2

You can for example use the switchMap operator if you have a network call that needs to use the result of a previous network call:

const combined$ = jwtAuthenticationService.requestToken()
    .switchMap(tokenBody => this.http.get('/someurl') );

This is the marble diagram:

// requestToken

|---------------T---| 

// second HTTP request

                   |------R--|

// combined$

|--------------------------R--|

The sequence goes like this:

  • subscription to requestToken occurs
  • token returns, first call observable completes
  • the result of requestToken is taken and the initial Observable is transformed via switchMap into a second Observable
  • if the initial observable had not completed, combined$ would have unsubscribed from it
  • a second observable is made for the second network call, that uses the result of the first
  • second call returns, second observable completes, combined$ completes
Angular University
  • 42,341
  • 15
  • 74
  • 81