3

I'm trying to set a token value in all request headers using angular 5 new HTTP client. Below is my code:

import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
import {Observable} from "rxjs/Observable";
import { Storage } from '@ionic/storage';
import {Globals} from '../globals/globals';

@Injectable()
export class Interceptor implements HttpInterceptor {
  token: string;
  constructor(private storage: Storage, private global: Globals){ 
    this.storage.get('token').then((val) => {
      this.token = val;
    });
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.log(this.token) //undefined "only for first time on app start"
    req = req.clone({
      setHeaders: {
        'Token': this.token,
        'Version': this.global.version,
      }
    });
    return next.handle(req);
  }
}

While adding the token in request header works, but there is a bad exception. It doesn't work for the first time. The problem is with js async nature, req.clone gets executed before getting token from the storage. Because Ionic storage returns promise, so how to handle this situation for the first time?

1 Answer 1

4

You can merge both async request (getting the token and handling the request) to execute the later when the token is ready (instead of getting it in the constructor):

// -------------------------------------------------------------------------
// Please note that I'm using lettable/pipeable operators (RxJS > 5.5.x)
// https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md
// -------------------------------------------------------------------------

import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from "rxjs/Observable";
import { Storage } from '@ionic/storage';
import { Globals } from '../globals/globals';

// New imports!
import { fromPromise } from 'rxjs/observable/fromPromise';
import { mergeMap } from 'rxjs/operators/mergeMap';

@Injectable()
export class Interceptor implements HttpInterceptor {

  constructor(private storage: Storage, private global: Globals){ }

  getToken(): Promise<any> {
    return this.storage.get('token');
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return fromPromise(this.getToken()).pipe(
        mergeMap(token => {

            // Use the token in the request
            req = req.clone({
                setHeaders: {
                    'Token': token,
                    'Version': this.global.version,
                }
            });

            // Handle the request
            return next.handle(req);
        }));
  }
}
Sign up to request clarification or add additional context in comments.

6 Comments

Hi @sebaferreras, thanks for the help! Unfortunately it is giving me error on return fromPromise(this.getToken).pipe( such as Argument of type '(): Promise<any>' is not assignable to parameter of type 'PromiseLike<{}>' property 'then' is missing in '(): Promise<any>'.
Oh what a silly mistake. That line should be return fromPromise(this.getToken()).pipe (notice the () after getToken) to actually call that method. @nishilbhave
Ohh yeah! It worked like a charm. Thank you so much bro.
this works well thank you, its weird that we have to do this in order to use the data from storage out of the scope of the storage.get() promise.
Glad to hear that it helped @George. Yeah, sometimes working with async methods may seem a little bit tricky.
|

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.