https://unsplash.com/photos/LmyPLbbUWhA
在上一篇「【Spring Boot】第22.1課-使用 RestTemplate 存取外部 API」文章,介紹了 RestTemplate 的操作方式,並存取一些測試用的 API。
而本文將分享 2 個串接外部服務的實例,出處均來自於筆者工作中遇到的需求。分別是提供 IP 所在地資訊的「ipapi」,以及提供匯率的「Currencylayer」。
一、用 ipapi 取得 IP 位置資訊
「ipapi」這項服務,能提供 IP 所在地的相關資訊,且無需註冊。使用額度方面,目前每日有 1000 次的免費額度(以前好像比較少,筆者不記得了)。
(一)背景
筆者前公司的產品提供了 Android 和 iOS 版的手機 App,所以網頁畫面上會出現 Play 商店跟 App Store 的下載頁面連結。然而中國是不能使用 Play 商店的,於是前端起初便呼叫 ipapi 的服務,藉此得知使用者 IP 所在地的資訊。若位於中國,則判定不顯示 Play 商店的連結。
但該服務是有每日的免費使用額度。為避免內網的多臺電腦共用同一 IP,直接呼叫該 API 卻把額度用光,因此改成由後端統一查詢。這項結果也能存入 DB,日後就優先從 DB 查。除非後端也呼叫失敗(可能額度用完了),才由前端直接呼叫 ipapi,甚至能進一步存回後端。
(二)API 規格
讓我們來看看 ipapi 能提供什麼資訊。
如圖,呼叫「GET https://ipapi.co/IP位置/json」,得到的 response 內容有:城市、幣別、經緯度、時區、手機國碼等等。
(三)程式實作
接下來就開始使用 RestTemplate 串接 ipapi。按照慣例,要先決定我們想要拿取哪些欄位,才能設計出用來接收 response 的類別。
然後再設計一個元件,將 RestTemplate 封裝起來。
範例程式中的「init」方法,會用 builder 的方式對 RestTemplate 做客製化設定。例如 API 路徑的前綴和逾時時間。
(四)測試
最後實際測試一下上面實作好的「IpApiClient」。
以上範例是查詢美國舊金山的一個公有 IP。而以下是試圖查詢私有 IP 的資訊。
可以看到,私有 IP 是不能查詢的。另外,查詢「127.0.0.1」(localhost)也會得到這樣的結果。
二、用 Currencylayer 取得匯率
「Currencylayer」這項服務,能提供 168 個幣別的匯率,包含歷史匯率。
使用此服務前需註冊。對於免費帳號,目前每月有 1000 次的查詢額度,且每日會更新一次匯率。若系統不要求一定要很新的即時匯率,選擇免費方案也不壞。
但免費方案只能查詢美金對其他幣別的匯率,不能查詢像是臺幣對日圓、歐元對澳幣等組合。
(一)背景
試想使用者在觀看產品列表時,可以用不同的幣別呈現價格,甚至是排序。那麼系統中就要有一個匯率表,用來將當初建立產品資料時所輸入的幣別與價格,換算成使用者想看的幣別。
原本筆者前公司是串接一個叫做「Free Forex API」的服務。但撰寫此文時,發現網站上寫說要與另一個叫做「Currencylayer」的服務合作,故本文將會以後者為串接的對象。
(二)API 規格
讓我們來看看 Currencylayer 的 API 使用方式。註冊帳號後,會得到一組 access_key。進到 dashboard 後,可實際在畫面上呼叫 API 做嘗試。
API 的呼叫方式為「GET http://apilayer.net/api/live?format=1&source=基礎幣別¤cies=目標幣別清單,英文逗號分隔&access_key=帳號的存取KEY」
發送請求後,得到如下的 JSON 資料。
(三)程式實作
接下來就開始使用 RestTemplate 串接 Currencylayer。一樣要先決定想要拿取的欄位,再設計出用來接收 response 的類別。
然後設計一個元件,將 RestTemplate 封裝起來。
實作方式與上一節大同小異。要注意的是使用 RestTemplate 時,API 路徑上的 url 至少要保留一個階層(此處保留「/live」),否則會拋出例外說「URI is not absolute」。
(四)測試
最後實際測試一下上面實作好的「CurrencyLayerClient」。
以上範例是查詢美金對臺幣、日圓、人民幣與歐元的匯率。其他支援的幣別,有興趣的讀者請參考官方文件。
三、以介面來使用 Client 元件
(一)背景
本文介紹了 IP 資訊和匯率的第三方服務。在範例程式中,client 元件與 response 物件也都根據它們的規格來實作。
但若有一天我們需要更換成新服務(例如第二節提到筆者前公司使用的匯率服務即將過時),那麼所有使用舊 client 與 response 類別的地方也都需要改動,畢竟已經無法再適用於新服務。
考慮到未來更換服務時,會遇到改動太多程式碼的不便,其實我們一開始就可以設計成透過「介面」來使用 client 元件與 response 類別。
還有另一個好處是促進團隊分工。可以讓一個人先去物色適合專案的第三方服務,並實作出 client 元件。而其他人也能同時依據該介面,著手開發業務邏輯。
(二)定義介面
以第一節的 IP 服務為例,我們希望能使用固定的介面,獲取需要的資訊。因此以下設計一個介面。
接下來也為 client 元件定義介面。此介面方法很單純,傳入 IP 地址,回傳帶有 IP 資訊的介面物件。
定義好介面後,便能套用到需要的地方了。請回到第一節實作的測試程式,將注入的元件、client 元件的呼叫,以及資訊的取得,都調整成以介面來溝通。
(三)實作介面
介面勢必有它的實體類別(concrete class)。定義好介面後,讓我們在 client 元件與 response 類別實作介面
以下是讓 client 元件類別實作。
以下是讓負責攜帶資料的 response 類別實作。
由於已經定義好介面了,因此未來更換服務時,也能比照辦理,只要提供實作類別即可。至於第二節的匯率服務,筆者亦在本文的完成專案中進行重構,有興趣可參考。
本文的完成專案:
https://github.com/ntub46010/SpringBootTutorial/tree/Ch22-2
留言
張貼留言