使用RxJS从多个API调用构建数据 [英] Using RxJS to build data from multiple API calls

查看:55
本文介绍了使用RxJS从多个API调用构建数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图更好地了解如何使用RxJS运算符来解决我遇到的特定问题.我实际上有两个问题,但它们足够相似.

I'm trying to get a better understanding of how to use RxJS Operators to solve a specific problem I'm having. I actually have two problems but they're similar enough.

我正在从API端点/api/v3/folders/$ {folderId}/documents 抓取一堆文档,并且我已经设置了具有此功能的服务,并处理了所有这些功能认证等.

I'm grabbing a bunch of documents from an API endpoint /api/v3/folders/${folderId}/documents and I've setup services with functions to do that, and handle all of the authentication etc.

但是,此文档对象数组具有description属性.为了获得描述,我需要在上一次调用的每个文档上调用/api/v3/documents/$ {documentId}/.我的文档界面如下所示:

However, this array of document objects does not have the description attribute. In order to get the description I need to call /api/v3/documents/${documentId}/ on each document from the previous call. My document interface looks like this:

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

我想我需要使用 mergeMap 等待并获取文档,以一些方式将其添加到我的 Document 界面中,然后返回整个内容,但是我无法获得最终结果.

I'm thinking I need to use mergeMap to wait and get the documents some how to add in the description onto my Document interface and return the whole thing, however I'm having trouble getting the end result.

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%为我解决问题.

This may seem like a bit of a duplicate but any post I've found hasn't 100% cleared things up for me.

非常感谢您了解如何在第二次调用中正确使用数据并将其包装在一起的任何帮助.谢谢.

Any help in understanding how to properly use the data in the second call and wrap it all together is much much appreciated. Thank you.

感谢@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().我将此更改应用于我的服务功能,该功能更新了行为主题,并且运行良好.谢谢!

For some reason I was unable to pipe() from the second service subscription so I ended up having to make the http.get call there. The error was "Cannot use pipe() on type subscription" which is a bit confusing, since I'm using pipe() on the first subscription. I applied this change to my service function that updates a behavior subject and it's working perfect. Thanks!

推荐答案

有多种不同的方法可以从多个api调用中组合数据.

There are a couple different ways to compose data from multiple api calls.

我们可以:

  • 使用 from 将每个项目分别发送到流中
  • 使用 mergeMap 订阅辅助服务调用
  • 一旦所有单个调用完成,
  • 使用 toArray 发出一个数组
  • use from to emit each item into the stream individually
  • use mergeMap to subscribe to the secondary service call
  • use toArray to emit an array once all the individual calls complete
  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

此外,您可以考虑将流定义为变量 documents $ ,而不是方法 getDocuments().

Also, you may consider defining your stream as a variable documents$ as opposed to a method 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()
  );

这篇关于使用RxJS从多个API调用构建数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆