Как запустить HTTP-запрос в al oop и получить статус каждого отдельного запроса - PullRequest
1 голос
/ 13 июля 2020

У меня есть массив объектов, и каждый из его объектов должен быть обновлен в базе данных с помощью HTTP-запроса на размещение.

[
{id: "3e81731f-e3b4-405d-a5ca-bef52c1b036a", date_created: "2019-07-24T15:55:31.372460Z", date_modified: "2020-07-13T03:25:02.720870Z", einsight_uuid: "d15176ab-ecf8-dba1-e040-10ac316407fa", attributes: {…}},
{id: "4707bff2-8265-456f-a4d4-ca1134d85620", date_created: "2019-07-24T15:55:31.372460Z", date_modified: "2020-07-13T03:25:06.238019Z", einsight_uuid: "fcda4259-3ecb-4566-85b0-5b6d5c7647f6", attributes: {…}}
{id: "d29a3340-04b6-431b-8671-a0f0d25a9b51", date_created: "2019-07-24T15:55:31.3724", date_modified: "2020-07-13T03:25:06.238019Z", einsight_uuid: "fcda4259-3ecb-4566-85b0-5b6d5c7647f6", attributes: {…}}
]

как я могу вызвать API для сохранения каждой записи в массиве. Вызов Api в al oop - простой вариант, но его недостаточно. Я хочу вести учет каждого ответа. сколько из них удалось или не удалось. Есть ли какая-либо известная передовая практика для выполнения такого рода действий в angular или rx js

Ответы [ 3 ]

1 голос
/ 13 июля 2020

Вы можете делать это либо параллельно, либо последовательно, в зависимости от количества запросов и ваших требований.

Параллельные запросы

Используйте Rx JS forkJoin функция с операторами tap и catchError. Попробуйте следующий

import { forkJoin, of, from } from 'rxjs';
import { tap, catchError, concatMap } from 'rxjs/operators';

putDataParallel() {
  let success = 0;                   // <-- trivial counters
  let errors = 0;

  const reqs = this.urls.map(url =>  // <-- replate `this.urls` with your object array
    this.http.put(url).pipe(         // <-- replace `url` with your own PUT request
      tap(_ => success++),           // <-- count successful responses here
      catchError(err => {        
        errors++;                    // <-- count errors here
        return of(err);              // <-- remember to return an observable from `catchError`
      })
    )
  );

  forkJoin(reqs).subscribe(
    null,                            // <-- you could change response callback to your requirement
    err => console.log(err),
    () => console.log(`Success: ${success}\nErrors: ${errors}`),
  );
}

Последовательные запросы

Используйте функцию Rx JS from и оператор concatMap для последовательного потока данные. Попробуйте следующее:

import { forkJoin, of, from } from 'rxjs';
import { tap, catchError, concatMap } from 'rxjs/operators';

putDataSequential() {
  let success = 0;                      // <-- trivial counters
  let errors = 0;

  from(this.urls).pipe(                 // <-- replate `this.urls` with your object array
    concatMap(url => {
      return this.http.put(url).pipe(   // <-- replace `url` with your own PUT request
        tap(_ => success++),            // <-- count successful responses here
        catchError(err => {        
          errors++;                     // <-- count errors here
          return of(err);               // <-- remember to return an observable from `catchError`
        })
      )
    })
  ).subscribe(
    null,                               // <-- you could change response callback to your requirement
    err => console.log(err),
    () => console.log(`Success: ${success}\nErrors: ${errors}`),
  );
}

Оба метода будут работать до тех пор, пока все объекты в массиве не будут завершены, независимо от ошибок или ответов. Если вы, тем не менее, используете sh, чтобы прервать последовательность в случае ошибки, замените оператор return of(err); в операторе catchError, чтобы вместо этого выдавалось уведомление error или complete. Например, вы можете использовать Rx JS EMPTY constant: return EMPTY;.

Я использовал в качестве примера тривиальные счетчики. Вместо этого вы можете использовать объекты (например) для регистрации количества ответов / ошибок и соответствующего ввода для HTTP-запроса.

Рабочий пример: Stackblitz

0 голосов
/ 13 июля 2020

Как видите, каждый элемент будет обработан с помощью concateMap , и после выполнения запроса HTTP каждый массив элементов result будет обновлен. Есть несколько способов добиться такого результата. Это один из способов, показанных здесь.

 items =[
       {id: "3e81731f-e3b4-405d-a5ca-bef52c1b036a", name :'united', result:[]},
       {id: "4707bff2-8265-456f-a4d4-ca1134d85620", name: 'ind', result:[]},
       {id: "d29a3340-04b6-431b-8671-a0f0d25a9b51", name:'ru', result:[]},
       {id: "xxx-xxxx-xxxx-xxxxx", name:'', result:[]}
    ]



from(this.items)
    .pipe(
        concatMap(item => this.ob2(item.name).pipe(
          catchError(err=>of(err)),
          tap(result =>{
            if(result.length){
              item.result = result;
            }else{
              // error scenario can be handled here
            }
            console.log('Updated each item', item)
          })
        ))
    ).subscribe();
  }

DEMO

0 голосов
/ 13 июля 2020

вы можете использовать rx js concat, но concat остановится, если наблюдаемый выдает ошибку, поэтому вы можете использовать catchError для возврата нового наблюдаемого

import { of ,concat} from 'rxjs';
....
 data = [
    {id:1},
    {id:2},
    {id:-1},
    {id:2},

    ]
  constructor(private http:HttpClient){
    let httpReqs = this.data
          .map(i => 
              this.http.put(`https://jsonplaceholder.typicode.com/posts/${i.id}`,{})
              .pipe(catchError(err => of({err})))
              );

     concat(...httpReqs).subscribe(console.log)
    }

demo ??

проверьте это ? rx js concat

...