Angular HttpClient: если get () не удается, выполнить post () - PullRequest
1 голос
/ 07 мая 2020

У меня есть HttpClient, внедренный в службу. У меня есть BehaviorSubject, настроенный для отслеживания изменений этого значения. Я использую фиктивную базу данных с json -сервером. Моя служба может правильно выполнить get (), когда я даю ей то, что существует, но если я дам ей то, чего не существует, она выдаст 404. Я хочу, чтобы она выполнила post ().

Для объяснения реального мира: у пользователя есть календарь с ежедневным журналом для каждого дня. Если они выберут день, в который существует журнал, он получит () его. Но если они выберут день, когда он не существует, служба должна отправить () пустой день на сервер. Возвращаясь к этому дню, вы получите () пустой, созданный ранее.

Это то, что у меня есть до сих пор:

getCurrentDay(id: string) {
    this.http.get<DailyLog>(this.daysUrl + "/" + id).subscribe(data => {
      this._currentDailyLog.next(Object.assign({}, data));
    },
      error => {
        return console.log('Could not load daily log');
      }
    )
  }

Для будущих искателей вот ответ, который я получил с помощью @Poul Krujit. Мне пришлось изменить 2 вещи из его предложения: URL-адрес сообщения не может содержать / id, как get (), и вам нужно указать объект как второй параметр в сообщении ().

  getCurrentDay(id: string) {
    const url = `${this.daysUrl}/${id}`;

    this.http.get<DailyLog>(url).pipe(
      catchError(error =>
        error.status === 404
          ? this.http.post<DailyLog>(this.daysUrl, { "id": id, })
          : throwError(error)
      )
    ).subscribe({
      next: (data) => this._currentDailyLog.next({ ...data }),
      error: (error) => console.log('Could not load daily log:', error)
    });
  }

Ответы [ 2 ]

1 голос
/ 07 мая 2020

Вы можете использовать оператор catchError:

getCurrentDay(id: string) {
  const url = `${this.daysUrl}/${id}`;

  this.http.get<DailyLog>(url).pipe(
    catchError((error) => error.status === 404 
      ? this.http.post<DailyLog>(url)
      : throwError(error)
    )
  ).subscribe({
    next: (data) => this._currentDailyLog.next({ ...data })),
    error: (error) => console.log('Could not load daily log:', error)
  });
}
0 голосов
/ 07 мая 2020

Как показывает практика, вы не должны подписываться на Observable внутри службы. Это делает данные (или ошибку) недоступными для вызывающего абонента. Вместо подписки вы должны использовать операторы и возвращать Observable.

Давайте проведем рефакторинг вашей службы

export class SomeService {

  getCurrentDay(id: string) {
    return this.http.get<DailyLog>(this.daysUrl + "/" + id)
               .pipe(
                   /** catchError will be called if an exception is thrown
                   /*  and it expects you to return another Observable
                   /*  which is a great place to make another call
                    *  I assume post method will return newly created instance
                    */                   
                   catchError(err => this.http.post<DailyLog>(this.daysUrl + "/" + id)),
                   // also if you need to do some stuff within your service, you can use tap
                   tap(data => this._currentDailyLog.next(data))
                );
  }

}

Приведенный выше метод пытается получить данные, в случае возникновения ошибки он вызовет post api и вернет результат post. Кроме того, попутно обновляйте BehaviorSubject.

ПРИМЕЧАНИЕ: Поскольку служба больше не подписывается, вызывающий этот метод должен подписаться, чтобы все работало (Observables ленивы по умолчанию и не выполняются, пока не подписаны)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...