web-dev-qa-db-ja.com

Angular2-複数の依存する順次httpapi呼び出し

Angular2アプリを構築していますが、コンポーネントの1つで、前のAPI呼び出しに依存する複数のAPI呼び出しを行う必要があります。

私は現在、テレビ番組のリストを取得するためにAPI呼び出しを行うサービスを持っています。次に、ショーごとに、異なるAPIを複数回呼び出して構造をステップ実行し、ショーがPlexサーバーに存在するかどうかを判断する必要があります。

APIドキュメントは ここ

ショーごとに、次の呼び出しを行い、正しいデータを取得して、それが存在するかどうかを判断する必要があります:(変数<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>)が存在することを確認する必要があります。そうでない場合は、ショーが存在しないことを返す必要があります。もしそうなら、私はおそらくショーの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ショー)。初期リストを返して、準備ができたらavailableステータスで更新できますか。
  2. key="2"を取得するための最初のPlex呼び出しは、1回だけ実行する必要があります。ハードコーディングすることもできますが、代わりに、一度実行して記憶することはできますか?
  3. API呼び出しの数を減らす方法はありますか?表示フィルターを削除して、クライアントで結果を検索できることがわかりますが、これも理想的ではありません。
  4. 各ショーの4回の呼び出しは順番に実行する必要がありますが、各ショーの速度を並行して照会できます。これは達成可能ですか?

どんな考えでも大歓迎です!

8
Anthony Day

私があなたの質問を完全に理解しているかどうかはわかりませんが、これが私がしていることです:

最初の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);
}

これにより、loginserviceValidateUserメソッドが呼び出されます

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

}

ログインサービスで、監視可能なトークンを返す認証サービスを呼び出します。

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メソッドを呼び出し、応答時に、戻り情報に基づいて、有効な場合はログインサービスのloginUserメソッドを呼び出すことです。このチェーンは、必要な限り継続できます。クラスレベルの変数を設定して、チェーンの各メソッドで必要な情報を保持し、次に何をするかを決定できます。

また、サービスで返品をサブスクライブしてそこで処理できることにも注意してください。コンポーネントに戻る必要はありません。

さて、ここに行きます:

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
John Baird