加入可以在一个可观察对象中有条件地发生的多个 http 调用

Join multiple http calls that can happen conditionally in one observable

为了示例起见,假设我有一个名为客户端的实体:

interface Client {
   id: number
   name: string
   address: Address[]
}

interface Address {
   id: number
   street: string
}

在这种情况下,我无法在同一调用中更新客户端的 name 和他的 addresses

相反,我需要:

所以我想做的是加入可以在一个可观察对象中有条件地发生的多个 http 调用。

这是我目前拥有的:

updateClientAndClientAddresses(): Observable<Client> {       

   return of({}).pipe(
     ******* Conditionally make all the create addresses calls *******
     ******* Conditionally make all the update addresses calls *******
     *******   Then make the update name call *******

     switchMap(([updateNameResponse: Client, responseOfAllAddressesToBeCreated: Address, responseOfAllAddressesToUpdated: Address]) => {
    // Ideally here I will have the results of all the calls made so far.

    // Merge everything manually here
    return {
      ...updateClientCallResponse,
      addresses: [
        ...responseOfAllAddressesToBeCreated,
        ...responseOfAllAddressesToUpdated
      ]};
  }),
)
}

只是为了加强: 在调用更新名称之前,我需要检查是否:

然后我需要检查是否:

  1. 将地址分为两组:要创建的和要更新的。

    const addressesToBeCreated: Address[] = [ /* list of addresses to be created */ ];
    const addressesToBeUpdated: Address[] = [ /* list of addresses to be updated */ ];
    
  2. 分别收集创建和更新地址所需的 HTTP 请求。 (假设服务器响应内容是什么。)

    const createRequests: Observable<Address>[] = addressesToBeCreated.map(
      (address) => this.client.post(...) //  request server to save the address, and respond with the created address resource
    );
    
    const updateRequests: Observable<Address>[] = addressesToBeUpdated.map(
      (address) => this.client.put(...) //  request server to update existing address, and respond with the updated address resource
    );
    
  3. 使用运算符 forkJoinconcatMap 构造一个管道,告诉 RxJS 实际触发发送创建和更新请求,然后 return表示已创建和更新的地址。

    const savedAddresses$ = forkJoin(createRequests) //  trigger the bunch of HTTP requests that creates addresses
      .pipe(
        concatMap((createdAddresses) => {  //  now we have a list of created addresses
          return forkJoin(updateRequests)  //  next, trigger HTTP requests that updates addresses
            .pipe(
              map((updatedAddresses) => {  //  now we have the list of updated addresses
                return [                   //  emit a tuple of created and updated addresses down the pipeline
                  createdAddresses,
                  updatedAddresses
                ];
              })
            );
        })
      );
    

    savedAddresses$ 将是一个可观察对象,它发出一个包含两个元素的数组:一个已创建地址列表和一个已更新地址列表。

  4. 最后再调用一次更改客户端名称。

    const savedModels$ = savedAddresses$.pipe(
      concatMap((savedAddresses) => {
        return this.client.put(...)   //  request server to update client name, and return updated client model
          .pipe(
            map((updatedClient) => {  //  now we have the client object with updated name
              return [updatedClient, ...savedAddresses]; //  emit a tuple down the pipeline with three elements: client, list of created addresses, and list of updated addresses
            })
          );
      })
    );
    

    savedModels$ 将是一个 observable,它发出三个元素的数组:更新了名称的客户端模型、创建的地址列表和更新的地址列表。

  5. 至此,您终于可以“在这里手动合并所有内容”。您可以加入有关客户的数据,以及已创建和更新的地址。

    updateClientAndClientAddresses(): Observable<Client> {
      ... //  code from previous steps
    
      return savedModels$.pipe(
        map(([updatedClient, createdAddresses, updatedAddresses]) => {
          return {
            ...updatedClient,
            address: [
              ...createdAddresses,
              ...updatedAddresses
            ]
          };
        })
      );
    }