make successive http calls that depend on each other

18 views
Skip to first unread message

Kiflemariam Andom

unread,
Jun 8, 2019, 3:44:23 AM6/8/19
to Angular and AngularJS discussion
Hello,

While my solution is working, it is a bit hard to follow and just ugly to look at. It is on Angular 5. All the 3 apis reply text. The steps are the following:

Call api1(). If successful:

it returns a simple text 'ok'
it will create a server side cookie.
Then call api2() which makes use of the cookie created by api1()
api2() returns a string that I need to save in indexdb. Furthermore, I call two other promises that do something with the result and save the result in indexdb as well. if api2() failed to return positively, i need to display a simple alert message and not call the promises at all.

then call api3() which calls the backend to simply clearout the cookie it has created. That is if api1() was ok, regardless of anything that happens in between, i must always logout. The thing is though if it ends up being called before api2(), api2() replies 'anauthorized' since it can't find the cookie.

Note that my application doesn't create the cookies so have no access to them. If api1() didn't succeeded, i shouldn't try to logout as the backend replies with error in that case.


I hope I am making sense. So here is my approach currently which does work to some extent but have horrible flow and not capturing all error messages obviously. So can someone help me rewrite it to be more efficient, easy to follow and capture possible errors.

  public setUpApp(idToken): any {
    let vm
: any = this;
   
        vm
.apiService
         
.api1(idToken)
         
.toPromise()
         
.then(result => {
            console
.log("success fully authenticated and cookie created");
           
// result contains 'ok'
           
return result;
         
})
         
.then(data => {
            console
.log("result from api1 ", data);// 'ok'
            vm
.apiService
             
.api2()
             
.toPromise()
             
.then(key => {
               
if (key == null) {
                 
// the token is not attached yet
                  alert
('Token not attached to keys yet')
                 
return false;
               
} else {
                 
// we have an key here.
                 
// call promises that process the key
                  let promises
= [];

                 
// the key is probably OK and we can save the key
                  promises
.push(this.db.setKey(key));
                  promises
.push(
                   
this.db.createData(key)
                 
);

                 
/*
              https://stackoverflow.com/questions/31424561/wait-until-all-es6-promises-complete-even-rejected-promises

              Basically, we want to make sure the promises are resolved either way
              before we return to the next

              */


                 
const reflect = p =>
                    p
.then(
                      v
=> ({ v, status: "fulfilled" }),
                      e
=> ({ e, status: "rejected" })
                   
);

                 
Promise.all(promises.map(reflect)).then(function(results) {
                   
var success = results.filter(x => x.status === "resolved");
                 
});


                 
return key;
               
}
             
})
             
.then(key => {
                console
.log("call api3 to logout now");
                vm
.apiService.api3().subscribe(logOut => {
                  console
.log("logged out ", logOut);
               
},
                err
=>{
                 
// likely the cookie wasn't found so server don't know what to logout exactly
                  console
.log('error logging out from auth ', err)
               
}
               
               
);
             
});
         
})
         
.catch(err => {
            console
.log("err ", err);
         
});
   
   
 
}


 

Sander Elias

unread,
Jun 8, 2019, 5:40:23 AM6/8/19
to Angular and AngularJS discussion
Hi Kiflemariam,

You should not cast all things to promises, that makes your life so much harder.

newSetupApp(idToken) {
const keyHandler = async key => {
if (key) {
await this.db.setKey(key).catch(() => console.log('setDb Failed'));
await this.db.createData(key).catch(() => console.log('createDb Failed'));
}
console.log('done with promises');
return key;
};

this.apiService
.api1(idToken)
.pipe(
/** only proceed if the result is 'ok */
filter(result => result.includes('ok')),
switchMap(() => this.apiService.api2()),
/** the whole handling of the api2 result is a side-effect */
switchMap(keyHandler),
switchMap(() => this.apiService.api3())
)
.subscribe({
next(result) {
console.log('result', result);
},
error(err) {
console.log('an error occured', err);
}
});
}

If you have any question, don't hesitate to ask
Reply all
Reply to author
Forward
0 new messages