Angular2 - 多个依赖顺序 http api 调用

Angular2 - Multiple dependent sequential http api calls

我正在构建一个 Angular2 应用程序,其中一个组件需要进行多次 API 调用,这些调用依赖于之前的组件。

我目前有一项服务可以拨打 API 电话以获取电视节目列表。对于每个节目,然后我需要多次调用不同的 API 来遍历结构以确定该节目是否存在于 Plex 服务器上。

API 文档是 here

对于每个节目,我需要进行以下调用并获取正确的数据以确定它是否存在:(假设我们有变量 <TVShow>, <Season>, <Episode>

http://baseURL/library/sections/?X-Plex-Token=xyz 会告诉我: title="TV Shows" key="2"

http://baseURL/library/sections/2/all?X-Plex-Token=xyz&title=<TVShow>会告诉我:key="/library/metadata/2622/children"

http://baseURL/library/metadata/2622/children?X-Plex-Token=xyz会告诉我:index="<Season>" key="/library/metadata/14365/children"

http://baseURL/library/metadata/14365/children?X-Plex-Token=xyz 会告诉我:index="<Episode>" 这意味着我的情节存在。

回复在json,我删掉了很多多余的文字。在每个阶段,我都需要检查是否存在正确的字段 (<TVShow>, <Season>, <Episode>),以便它们可以用于下一次调用。如果没有,我需要return表示该节目不存在。如果是这样,我可能想要 return 节目的 ID。


我看过很多示例,包括 promise、async 和 flatmap,但我不确定如何根据我看到的其他示例解决这个问题。


这是我用来获取节目列表的信息。 (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;
}

这里是组件的相关代码(shows.component.ts)

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

奖励积分

以下是很明显的下一个问题,这些问题很有趣,但不是必需的:

  1. 第一个 API 查询比等待所有其他查询发生要快得多(4 个查询 * ~10 显示)。是否可以 return 编辑初始列表,然后在准备就绪时使用 available 状态更新。
  2. 获取 key="2" 的第一个 Plex 调用只需要执行一次。它可以是硬编码的,但是,它可以执行一次并记住吗?
  3. 有没有办法减少 API 调用的次数?我可以看到我可以删除显示过滤器,并在客户端上搜索结果,但这也不是很理想。
  4. 每个节目的 4 次调用必须按顺序完成,但每个节目可以并行查询以提高速度。这是可以实现的吗?

如有任何想法,我们将不胜感激!

不确定我是否完全理解你的问题,但我是这样做的:

我进行了第一个 http 调用,然后当订阅触发时,它调用了 completeLogin。然后我可以用它自己的完整功能触发另一个 http 调用并重复链。

这是组件代码。用户已填写登录信息并按下登录:

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);
}

这会调用 loginservice ValidateUser 方法

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']);
   }

}

在我的登录服务中,我调用了授权服务,return这是一个可观察的令牌。

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));
}

在授权服务中:

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())
}

这段代码的重点是,首先调用登录服务的validateUser方法,响应后,根据return信息,如果有效,我调用登录服务的loginUser方法.只要你需要,这条链就可以继续下去。您可以设置 class 级变量来保存您在链的每个方法中需要的信息,以决定下一步要做什么。

另请注意,您可以在服务中订阅 return 并在那里进行处理,而不必 return 到组件。

好的,开始:

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....
}