Angular2 - Several dependent consecutive http api calls

I am creating an Angular2 application, and one of the components must make several API calls, which depend on the previous ones.

I currently have a service that calls an API call to retrieve a list of TV shows. For each show, I need to call another API several times to go through the structure to determine if the show exists on the Plex server.

API documentation here

For each show, I need to make the following calls and get the correct data to determine if it exists: (suppose we have the variables <TVShow>, <Season>, <Episode> )

http://baseURL/library/sections/?X-Plex-Token=xyz will tell me: title="TV Shows" key="2"

http://baseURL/library/sections/2/all?X-Plex-Token=xyz&title=<TVShow> will tell me: key="/library/metadata/2622/children"

http://baseURL/library/metadata/2622/children?X-Plex-Token=xyz will tell me: index="<Season>" key="/library/metadata/14365/children"

http://baseURL/library/metadata/14365/children?X-Plex-Token=xyz will tell me: index="<Episode>" , which implies that I have an episode.

Answers in json, I deleted a lot of excess text. At each step, I need to verify that the correct fields exist ( <TVShow>, <Season>, <Episode> ) so that they can be used for the next call. If not, I need to return that the show does not exist. If this happens, I will probably want to return an identifier for display.


I looked at a lot of examples, including promise, asynchronous and flat cards, but I'm not sure how to solve this problem based on other examples that I saw.


Here is what I need to get the show list. (Shows.service.ts)

 export class ShowsHttpService { getShows(): Observable<Show[]> { let shows$ = this._http .get(this._showHistoryUrl) .map(mapShows) .catch(this.handleError); return shows$; } } function mapShows(response:Response): Show[] { return response.json().data.map(toShow); } function toShow(r:any): Show { let show = <Show>({ episode: r.episode, show_name: r.show_name, season: r.season, available : false, // I need to fill in this variable if the show is available when querying the Plex API mentioned above. }); // My best guess is here would be the right spot to call the Plex API as we are dealing with a single show at a time at this point, but I cannot see how. return show; } 

Here is the corresponding code from the component (shows.component.ts)

 public getShows():any { this._ShowsHttpService .getShows() .subscribe(w => this.shows = w); console.log(this.shows); } 

Bonus Points

Here are the obvious following interesting but optional questions:

  • The first API request will be much faster than waiting for all other requests (4 requests * ~ 10 shows). Whether the original list can be returned and then updated with the available state when it is ready.
  • The first Plex call to get key="2" needs to be done only once. It can be hardcoded, but instead, can it be done once and remembered?
  • Is there a way to reduce the number of API calls? I see that I can remove the show filter and perform a search on the client, but this is also not ideal.
  • 4 calls for each show must be performed in sequence, but each show can be requested in parallel for speed. Is it possible?

Any thoughts would be greatly appreciated!

+6
source share
1 answer

Not sure if I fully understand your question, but here is what I am doing:

I make the first http call, and then when the fire signs, it calls completeLogin. Then I could start another HTTP call with its own full function and retry the chain.

Here is the component code. The user filled in the registration information and clicked login:

 onSubmit() { console.log(' in on submit'); this.localUser.email = this.loginForm.controls["email"].value; this.localUser.password = this.loginForm.controls["password"].value; this.loginMessage = ""; this.checkUserValidation(); } checkUserValidation() { this.loginService.getLoggedIn() .subscribe(loggedIn => { console.log("in logged in user validation") if(loggedIn.error != null || loggedIn.error != undefined || loggedIn.error != "") { this.loginMessage = loggedIn.error; } }); this.loginService.validateUser(this.localUser); } 

This calls the loginservice ValidateUser authentication method

 validateUser(localUser: LocalUser) { this.errorMessage = ""; this.email.email = localUser.email; var parm = "validate~~~" + localUser.email + "/" var creds = JSON.stringify(this.email); var headers = new Headers(); headers.append("content-type", this.constants.jsonContentType); console.log("making call to validate"); this.http.post(this.constants.taskLocalUrl + parm, { headers: headers }) .map((response: Response) => { console.log("json = " + response.json()); var res = response.json(); var result = <AdminResponseObject>response.json(); console.log(" result: " + result); return result; }) .subscribe( aro => { this.aro = aro }, error => { console.log("in error"); var errorObject = JSON.parse(error._body); this.errorMessage = errorObject.error_description; console.log(this.errorMessage); }, () => this.completeValidateUser(localUser)); console.log("done with post"); } completeValidateUser(localUser: LocalUser) { if (this.aro != undefined) { if (this.aro.errorMessage != null && this.aro.errorMessage != "") { console.log("aro err " + this.aro.errorMessage); this.setLoggedIn({ email: localUser.email, password: localUser.password, error: this.aro.errorMessage }); } else { console.log("log in user"); this.loginUser(localUser); } } else { this.router.navigate(['/verify']); } 

}

In my login service, I call the authorization service, which returns the observed token.

 loginUser(localUser: LocalUser) { this.auth.loginUser(localUser) .subscribe( token => { console.log('token = ' + token) this.token = token }, error => { var errorObject = JSON.parse(error._body); this.errorMessage = errorObject.error_description; console.log(this.errorMessage); this.setLoggedIn({ email: "", password: "", error: this.errorMessage }); }, () => this.completeLogin(localUser)); } 

In the authorization service:

 loginUser(localUser: LocalUser): Observable<Token> { var email = localUser.email; var password = localUser.password; var headers = new Headers(); headers.append("content-type", this.constants.formEncodedContentType); var creds:string = this.constants.grantString + email + this.constants.passwordString + password; return this.http.post(this.constants.tokenLocalUrl, creds, { headers: headers }) .map(res => res.json()) } 

The point here in this code is to first call the validateUser method of the login service, after responding based on the returned information, if it is valid, I call the loginUser method in the login service. This chain can continue as long as you need it. You can set class level variables to store the necessary information in each method in the chain to make decisions about what to do next.

Please note that you can sign up for a return to the service and process it there, it does not need to return to the component.

Ok, here goes:

 public getShows():any { this._ShowsHttpService .getShows() .subscribe( w => this.shows = w, error => this.errorMessage = error, () => this.completeGetShows()); } completeGetShow() { //any logic here to deal with previous get; this.http.get#2() .subscribe( w => this.??? = w), error => this.error = error, () => this.completeGet#2); } completeGet#2() { //any logic here to deal with previous get; this.http.get#3() .subscribe( w => this.??? = w), error => this.error = error, () => this.completeGet#3); } completeGet#3() { //any logic here to deal with previous get; //another http: call like above to infinity.... } 
+3
source

All Articles