呼叫多次API Observable處理問題

覺得自己的問題有點抽象,所以用情境的方式描述
情境一:
如果想呼叫兩次API,且都是回傳Observable
那如果先第一次呼叫API先取得會員資料,然後根據取得的會員資料中的ID後,再呼叫一次API去取得此ID所購買的商品列表,請問如果使用Observable有什麼樣的operator適用這樣的情境呢?

目前想到的是第一個API subscribe後,在裡面在呼叫第二個API,不曉得是否有更好的做法

情境二:
當使用者填好資料要送出時,但裡面有三個欄位,分別要call三個不同API進行驗證,再把驗證失敗的訊息一次顯示出來,這樣的情境又可以使用哪種operator呢?是使用concat嗎?或是有更好的實作方式 ?

1個讚

情境一: mergeMap

this.http.get('...').pipe(
    mergeMap((value)=>{
       return this.http.get('..../'+value);
   })
)

情境二: forkJoin

forkJoin(
   api1,
   api2, 
   api3
).subscribe((value)=>{
  //  value[0] from api1
  //  value[1] from api2
  //  value[2] from api3
})
3個讚

感謝kevin大大的解答~~~馬上來試試

想請教另外一種情境,其實跟原本的情境類似
描述如下 :
[問題] 想呈現產品資訊在表格中,且品牌為中文,非代碼
目前有一個rest api 會回傳 Observable<Product[]> (一次會傳多個產品)
而產品的品牌(Product.brand)是自行定義的code,例如ASUS好了。
而目前希望在產品列表中品牌那一欄顯示的是華碩,而不是ASUS,所以必須在呼叫一個API用ASUS的key取得華碩這個Value。

[目前的想法]
let productGrid;Product[]; //產品列表

let $product = http.get(…) -> 回傳產品陣列的observable
let $codeNameMapping = http.get(…) -> 回傳產品陣列中所有產品對應中文名稱的observable

再採用 forkjoin

forkjoin($product ,$codeNameMapping ).subscribe(result=>{
result[0].brand = result[1];
this.productGrid.add(result[0]);
)}

[問題點] 在建立codeNameMapping 不知道該如何建立,目前就卡在這裡
$codeNameMapping = $product.mergeMap(products => {
products.forEach(product=>product.brand);
return ??? -> 不知道要怎麼處理
})

想請教此種情境該如何著手呢 ? 是我的想法有誤呢? 或是其實有更乾淨的做法。@@"

思考方向
從 product$ 將產品資料取回來後,利用 from 的方法將陣列打算,然後再分別去叫 codeNameMapping$ API. (這個可以在包成有 cache 功能的 functions)
最後再用 toArray 的方式組回陣列

product$.pipe(
    mergeMap(x=> from(x)),
    mergeMap(product=> this.http.get(`..../${product.brand}`)
                           .pipe(
                               map(brandName=> ({...product, brandName: brandName})
                            ),
   toArray()
   )
)
1個讚

我會用switchMap+toArray的作法
概念跟 kevin 的很像,就是把array扁平化然後再重新變成array

這邊我先用5.x的寫法,還沒習慣新的寫法QQ

$product.pipe(
 switchMap(products => $codeNameMappinp, (codes, product) => {
     product.codeData = codes.find(c=>c.brand === product.brand);
     return product;
 }),
 toArray()
)

謝謝兩位提供的建議與參考 ^^

這樣想到另一個問題,那如果未來要轉換的欄位不只一個,可能除了品牌,又多了用途(另一個code2name的api)之類的轉換.是不是就會使用多次的mergeMap,有十個code2name api,
,就要再加十個mergeMap @@

product$.pipe(
mergeMap(x=> from(x)),
mergeMap(product=> this.http.get(..../${product.brand})
.p≤ipe(
map(brandName=> ({…product, brandName: brandName})
),
mergeMap(product=> this.http.get(..../${usage})
.pipe(
map(usage=> ({…product, usage: usage})
),
mergeMap(product=> this.http.get(..../${otherAttributeCode})
.pipe(
map(otherAttributeName=> ({…product, otherAttributeName:otherAttributeName})
),
toArray()
)
)

所以類似這種情況,直接請後端改 API 會比較好

1個讚

我串過四五個的…就已經想要叫後端處理
我們不是葉問不要打十個XD

1個讚