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

api http service angular observable

8890 просмотра

1 ответ

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


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


Вот что у меня есть для получения списка шоу. (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. Первый вызов Plex для получения key="2"единственного необходимо выполнить один раз. Это может быть жестко закодировано, но вместо этого, можно ли его выполнить один раз и запомнить?
  3. Есть ли способ уменьшить количество вызовов API? Я вижу, что могу удалить фильтр показа и выполнить поиск по результатам на клиенте, но это тоже не идеально.
  4. 4 вызова для каждого шоу должны быть сделаны последовательно, но каждое шоу может запрашиваться параллельно для скорости. Это достижимо?

Любые мысли будут высоко ценится!

Автор: Anthony Day Источник Размещён: 08.11.2019 11:17

Ответы (1)


3 плюса

Решение

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

Я делаю первый 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);
}

Это вызывает метод ValidateUser loginservice

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....
}
Автор: John Baird Размещён: 20.08.2016 02:15
Вопросы из категории :
32x32