Angular2-несколько зависимых последовательных вызовов http api



Я создаю приложение Angular2, и один из компонентов должен сделать несколько вызовов 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>), чтобы их можно было использовать для следующего вызова. Если нет, то мне нужно ... верните, что шоу не существует. Если это произойдет, я, вероятно, захочу вернуть удостоверение личности для шоу.





Я посмотрел на множество примеров, включая promise, async и flatmap, но не уверен, как решить эту проблему на основе других примеров, которые я видел.




Вот что у меня есть для получения списка шоу. (покажет.обслуживание.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;
}


Вот соответствующий код из компонента (показывает.деталь.ts)



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




Бонус пункты



Вот очевидные следующие вопросы, которые интересны, но не являются необходимыми:


  1. первый запрос API будет намного быстрее, чем ожидание выполнения всех остальных запросов (4 запроса * ~10 показывает). Может ли первоначальный список быть возвращен, а затем обновлен со статусом available, когда он будет готов.

  2. первый вызов Plex, чтобы получить key="2", должен быть выполнен только один раз. Он может быть жестко закодирован, но вместо этого его можно выполнить один раз и вспомнил?

  3. есть ли способ уменьшить количество вызовов API? Я вижу, что могу удалить фильтр показа и выполнить поиск по результатам на клиенте,но это тоже не идеально.

  4. 4 вызова для каждого шоу должны выполняться последовательно, но каждое шоу может быть запрошено параллельно для скорости. Достижимо ли это?

Любые мысли были бы очень признательны!

933   1  

1 ответ:

Не уверен, что я полностью понимаю ваш вопрос, но вот что я делаю:

Я делаю первый вызов http, затем, когда срабатывает subscribe, он вызывает completeLogin. Затем я мог бы запустить еще один вызов http с его собственной полной функцией и повторить цепочку.

Вот код компонента. Пользователь заполнил данные для входа и нажал 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);
}

При этом вызывается метод 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']);
   }

}

В моем сервисе входа в систему я делаю звонок к службе авторизации, которая возвращает наблюдаемый токен.

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

Comments

    Ничего не найдено.