user1692333
user1692333

Reputation: 2597

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.

Upvotes: 5

Views: 4423

Answers (1)

Ivar Reukers
Ivar Reukers

Reputation: 7719

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:

Upvotes: 5

Related Questions