Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible somehow call async Ionic Storage synchronously?

I'm trying to create a class for working with API on top of Angular2 HTTP class. The main thing is that I need to add custom auth header which is available after user authorized.

The main problem is that the token is stored in Ionic Storage module from which it can be only be obtained asynchronously, but I need to return the specific type....

export class APIRequest extends Http {

    private storage : Storage;

    constructor (backend: XHRBackend, options: RequestOptions) {
        super(backend, options);

        this.storage = new Storage;
    }

    request(url: string|Request, options?: RequestOptionsArgs): Observable<Response> {
        if (typeof url === 'string') {
            url = AppConfig.API_SERVER + url
        } else {
            url.url = AppConfig.API_SERVER + url.url
        }

        this.storage.get('authToken').then(token => {
            if (typeof url === 'string') {
                if (!options) {
                    options = {headers: new Headers()};
                }

                options.headers.set('Authorization', `Bearer ${token}`);
            } else {
                url.headers.set('Authorization', `Bearer ${token}`);
            }
            // Here I need to return 
        }, err => {
            // throw some error
        })

        return super.request(url, options).catch(this.catchAuthError(this));
    }
}

So basically I need somehow to put return super.request(url, options)... to the promise of the storage and return when i get that token.

like image 549
user1692333 Avatar asked Dec 13 '16 11:12

user1692333


1 Answers

Close to being a duplicate. (Couln't find it)

At least, the answer can be applied to the same problem. If you want to keep the returning Observable a fix would be to convert your Promise (this.storage.get) to an Observable.

After, you can use a operator like flapMap to return the value of super.request.

(Note: Compiler doesn't understand that it's returning a Response now, so change return type to Observable<any> (will still return Response))

export class APIRequest extends Http {

    private storage : Storage;

    constructor (backend: XHRBackend, options: RequestOptions) {
        super(backend, options);

        this.storage = new Storage;
    }
    // any return type (will return Response object but compiler doesn't understand that)
    request(url: string|Request, options?: RequestOptionsArgs): Observable<any> {
        if (typeof url === 'string') {
            url = AppConfig.API_SERVER + url
        } else {
            url.url = AppConfig.API_SERVER + url.url
        }

        //convert the Promise to an Observable
        val storageObservable = Observable.fromPromise(this.sotrage.get('authToken'));

        // rxjs/add/operator/mergeMap
        return storageObservable.flatMap(token => {
            if (typeof url === 'string') {
                if (!options) {
                    options = {headers: new Headers()};
                }

                options.headers.set('Authorization', `Bearer ${token}`);
            } else {
                url.headers.set('Authorization', `Bearer ${token}`);
            }
            // the value that will be returned
            return super.request(url, options).catch(this.catchAuthError(this));
        }, err => {
            // throw some error
        })


    }
}

Useful links:

  • documentation from reactivex.io . For instance, for flatMap: http://reactivex.io/documentation/operators/flatmap.html
  • Why we need to use flatMap?
like image 173
Ivar Reukers Avatar answered Sep 23 '22 06:09

Ivar Reukers