簡體   English   中英

使用 RxJS 從多個 API 調用構建數據

[英]Using RxJS to build data from multiple API calls

我試圖更好地了解如何使用 RxJS 運算符來解決我遇到的特定問題。 我實際上有兩個問題,但它們足夠相似。

我正在從 API 端點/api/v3/folders/${folderId}/documents抓取一堆文檔,我已經設置了具有執行此功能的服務,並處理所有身份驗證等。

但是,這個文檔對象數組沒有description 屬性。 為了獲得描述,我需要在上次調用的每個文檔上調用/api/v3/documents/${documentId}/ 我的文檔界面是這樣的:

export interface Document {
  id: number;
  name: string;
  description: string;
}

我在想我需要使用mergeMap等待並獲取文檔一些如何將描述添加到我的Document界面並返回整個內容,但是我無法獲得最終結果。

getDocuments(folderId: number) {
    return this.docService.getDocuments(folderId, this.cookie).pipe(
      map(document => {
        document; // not entirely sure what to do here, does this 'document' carry over to mergeMap?
      }),
      mergeMap(document => {
        this.docService.getDocument(documentId, this.cookie)
      }) // possibly another map here to finalize the array? 
    ).subscribe(res => console.log(res));
  }

這可能看起來有點重復,但我發現的任何帖子都沒有 100% 為我解決問題。

非常感謝任何有助於理解如何在第二次調用中正確使用數據並將其包裝在一起的幫助。 謝謝你。

感謝@BizzyBob,這是經過編輯和解釋的最終解決方案:

  getDocuments(folderId: number) {
    const headers = new HttpHeaders({
      'Content-Type': 'application/json',
      'Context': this.cookie$
    });
    return this.docService.getDocuments(folderId, this.cookie$).pipe(
      mergeMap(documents => from(documents)),
      mergeMap(document => this.http.get<IDocument>(
        this.lcmsService.getBaseUrl() + `/api/v3/documents/${document.id}`,
        { headers: headers }
      ).pipe(
        map(completeDoc => ({...document, description: completeDoc.description}))
      )),
      toArray()
    ).subscribe(docs => {
      this.documents = docs;
      console.log(this.documents);
    }
    )
  }

出於某種原因,我無法從第二個服務訂閱中使用pipe() ,所以我最終不得不在那里撥打http.get電話。 錯誤是“無法在類型訂閱上使用 pipe()”,這有點令人困惑,因為我在第一個訂閱上使用了pipe() 我將此更改應用到我的服務 function,該服務更新了行為主題並且運行良好。 謝謝!

由於您必須調用 document/{id} 端點來獲取描述,對於每個文檔,您最終將調用 rest 作為您擁有的文檔的數量。

mergeMap返回一個 observable 並在外部 observable 發出時訂閱它。 (與 switchMap 相比,保持內部訂閱有效) https://www.learnrxjs.io/learn-rxjs/operators/transformation/mergemap

Rxjs from獲取一個數組並通過按順序發射數組的每個項目返回一個可觀察對象。 https://www.learnrxjs.io/learn-rxjs/operators/creation/from

所以我們可以像這樣使用兩者來實現您的目標:

抱歉我使用手機的格式不正確

我假設 docService.getDocuments 返回一個文檔數組。

getDocuments(folderId: number) { 
    return this.docService.getDocuments(folderId, this.cookie).pipe(
      mergeMap((allDocumentsArray)=> {
             return from(allDocumentsArray).pipe(
               mergeMap((document) =>        
                   this.docservice.getDocument(document).pipe(
                        map(doc) => {...document,description})),//maps the document with document.description
     toArray(),//combines the returned values to an array
    ).subscribe(res => console.log(res));

我建議在他們的文檔中閱讀有關 mergemap 的內容。 並在使用之前測試這個,因為我還沒有測試過。

有幾種不同的方法可以從多個 api 調用中組合數據。

我們可以:

  • 使用from將每個項目分別發送到 stream
  • 使用mergeMap訂閱二次服務調用
  • 一旦所有單獨的調用完成,使用toArray發出一個數組
  getDocuments() {
    return this.docService.getDocuments().pipe(
        mergeMap(basicDocs => from(basicDocs)),
        mergeMap(basicDoc => this.docService.getDocument(basicDoc.id).pipe(
          map(fullDoc => ({...basicDoc, description: fullDoc.description}))
        )),
        toArray()
    );
  } 

我們還可以利用forkJoin

  getDocuments() {
    return this.docService.getDocuments().pipe(
      switchMap(basicDocs => forkJoin(
        basicDocs.map(doc => this.docService.getDocument(doc.id))
      ).pipe(
        map(fullDocs => fullDocs.map((fullDoc, i) => ({...basicDocs[i], description: fullDoc.description})))
      )),
    );
  }

這是一個工作的StackBlitz

此外,您可以考慮將 stream 定義為變量documents$而不是方法getDocuments()

  documents$ = this.docService.getDocuments().pipe(
    mergeMap(basicDocs => from(basicDocs))
    mergeMap(basicDoc => this.docService.getDocument(basicDoc.id).pipe(
      map(fullDoc => ({...basicDoc, description: fullDoc.description}))
    ))
    toArray()
  );

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM