2
\$\begingroup\$

I am trying to write an Angular service that will wrap the regular Http service and automatically make authentication calls if Bearer token is not available or invalid.

Here's an illustration of a regular GET call made via the service:

this.httpWithAutomagicAuth
    .get("http://localhost:5001/books")
    .map(res => res.json())
    .subscribe(
        data => {
            self.data = data;
        }
    );

And here's my very sloppy implementation for such service. Obviously, I'm not using the right ReactiveX idioms in the code.

As you can easily notice I am trying to build an observable (Observable.create) that is using another observable returned by this.login(). I am sure there is a better way of chaining/nesting observable for this scenario.

Please, suggest improvements that will make code:

  • terse
  • easy to read and understand

    @Injectable()
    export class HttpWebApiAuthService {
    
    constructor(private http: Http) { }
    
    // ...
    
    public get(url: string, options?: RequestOptionsArgs): Observable<Response> {
        // TODO this code is for test purpose only (basically, it required to enforce the jwtToken retrieval branch execution)
        // this.clearJwtToken();
    
        if (!this.getJwtToken()) {
            return Observable.create(
                (result: Observer<Response>) => {
                    this.login()
                        .map(res => res.json())
                        .subscribe(
                            data => {
                                this.saveJwtToken(data.id_token);
    
                                this.executeGet(url, options)
                                    .subscribe(authenticationResult => {
                                        result.next(authenticationResult);
                                    });
                            },
                            error => { console.error("Authentication error", error); },
                            () => { console.info("Authentication complete"); }
                        );
                    },
                    error => { console.error("OBSERVABLE error: ", error); },
                    () => { console.info("OBSERVABLE complete");
                }
            );
        } else {
            return this.executeGet(url, options);
        }
    }
    
    private login() : Observable<Response> {
        const authBody =
            {
                "client_id": "...",
                "username": "...",
                "password": "...",
                // ...
            };
        const headers = new Headers();
        headers.append("Content-Type", "application/json");
    
        return this.http.post("https://AUTH_URL", JSON.stringify(authBody), { headers: headers });
    }
    
    // ...
    
    }
    
\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

I had to use flatMap to achieve what I wanted:

public get(url: string): Observable<Response> {
  return this
    .login()
    .flatMap(token_id => this._http.get(url));  // token_id can be used here
}

public login(): Observable<string> {
  const authBody =
      {
          "client_id": "...",
          "username": "...",
          "password": "...",
          // ...
      };
  const headers = new Headers();
  headers.append("Content-Type", "application/json");

  return this._http
    .post('AUTH_URL', authBody)
    .map(response => response.json().token_id);
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.