Mehran
Mehran

Reputation: 16901

How to inject an HTTP request before user's request is sent

I'm learning Angular and as a part of, I'm trying to see how can I implement a use-case that I have in mind. At this point, I'm trying to test server communication. Namely, RxJs' Observables.

The use-case that I have in mind, is sending a POST request which requires an X-XSRF-TOKEN header to be accepted on the server side. This is a security header sent back to the client as a cookie the first time it sends a GET request. In other words, no conversation with the server can start with a POST request.

The way I was hoping to implement this is by wrapping the Angular's Http class:

import {Http, RequestOptions, RequestOptionsArgs, Response} from '@angular/http';
import { Injectable} from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { CookieService } from 'angular2-cookie/services/cookies.service';

@Injectable()
export class RestClient {
  private static xsrfTokenCookie: string = 'XSRF-TOKEN';
  private static xsrfTokenHeader: string = 'X-XSRF-TOKEN';
  private static xsrfToken: string = null;

  constructor(private http: Http, private cookies: CookieService) {}

  get(url: string, options?: RequestOptionsArgs): Observable<Response> {
    return this.http.get(url, options);
  }

  post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
    if (!options) {
      options = new RequestOptions(new Headers());
    }
    if (!RestClient.xsrfToken) {
      RestClient.xsrfToken = this.cookies.get(RestClient.xsrfTokenCookie);
    }
    if (!RestClient.xsrfToken) {
      //TODO: Somehow construct an Observable object which once subscribed, it will make a GET request
      // then using the returned cookie, it will construct the actual POST request.
    }
  }
}

So my question is, how can I compose a POST request which sends a GET request first, waits for its response and then it will send the actual POST request. Of course, the returned Observable which post method's caller will get, belongs to the POST request, not the GET request. So if I write:

restClient.post('/', {}).subcribe(response => {
  //It's POST's response
})

Upvotes: 0

Views: 1247

Answers (2)

Jota.Toledo
Jota.Toledo

Reputation: 28454

Use mergeMap:

    post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
        if (!options) {
          options = new RequestOptions(new Headers());
        }
        if (!RestClient.xsrfToken) {
          RestClient.xsrfToken = this.cookies.get(RestClient.xsrfTokenCookie);
        }
        if (!RestClient.xsrfToken) {
          return this.getToken(...)
                 .mergeMap(token => this.postToServer(...));
        }
      }
    }

In this case, getToken could be a private method that returns an Observable with the token value. The same applies for postToServer, but with return type Observable of Reponse. By creating concatenable minimal focused methods you are capsulating the logic into pieces, and by making them private you hide the implementation details.

Upvotes: 1

Vamshi
Vamshi

Reputation: 9341

Use flatMap. In case you want to ignore previous request when a new request is triggered, you can use switchMap.

return get(getUrl,....)
   .switchMap( response => restClient.post(url, response.token .... )

This will return the Observable of post call.

Upvotes: 1

Related Questions