使用 Retrofit 簡化網路 API 整合

Kevin Chung
7 min readDec 22, 2020

--

Photo by Compare Fibre on Unsplash

App 的開發者如果有使用到網路上提供的服務,對於 REST API 介面一定不陌生,一些較具規模的服務商(例如像 Google)可能會提供給你各種語言的 SDK,只要將 SDK 整合到 project 後,就能簡單的透過 function call 來存取各種服務。

不過大部份的時候,服務端只提供介面定義,開發者就需要根據這些規格來自己整合 API 服務,尤其是自己也有開發後端。

由 client 端發出 HTTP 的 POST/GET Request,取得 server 端 JSON 格式的 Response 幾乎是目前的標準化流程與格式了,這裡利用電子發票 API 來當作例子。

電子發票的規格可以在這裡下載,如果要使用服務請記得填寫申請書提出申請,幾天內就會收到回覆,順利的話就能取得 API key。

我們先以取得發票中獎號碼清單當作例子,我們先使用 java 標準函式庫來進行開發,首先是一個通用的 function 來進行 HTTP POST,它有兩個參數分別是 endpoint 路徑與 query 參數。

電子發票的 API 雖然是用 POST method,參數卻不是 form 格式,而是 query 字串的方式傳遞的

從上面的程式碼可以看得出來,使用標準的 HttpsURLConnection 函數很麻煩,得處理很多細節,這裡就不解釋了,因為我們馬上就可以把這樣的程式碼給遺忘了。

接著是處理 API 的 query string,從規格書裡可以找到需要的參數數目與型別:

利用 queryString 這個字串變數,因為參數的內容有固定的文字,所以不需要 URLEncode 特別處理過,只要直接串連起來然後丟入剛剛寫好的 httpPost function裡。

查詢中獎發票的 API 路徑在文件裡,定義成常數即可

最後處理回傳的 JSON 格式回應字串,定義節錄如下

先定義好物件格式

接下來寫程式把 JSON 物件轉成 Java 物件

這樣就很簡單的完成了一個 API 的整合了,不過這個程式碼的數量是不是太多了?如果後面還有十幾個 API 那就真是太辛苦了,趕快來看看 retrofit 怎麼簡化開發的。

retrofit 是一個利用 Java annotation 機制來幫你產生代碼的函式庫,透過註解的字串,讓 API 的 code 看起來更有組織條理容易閱讀,而自動產生的樣板代碼更是讓開發者節省很多時間。

Dependency

首先在專案裡加入相關的依賴定義,包含了 retrofit 本身,以及處理 http 所需的 okhttp 套件,處理將 JSON 物件轉成 Kotlin 物件的 converter-gsonlogging-interceptor 對除錯蠻有幫助的,建議也可以加入。

dependencies {    
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:3.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
implementation "com.squareup.okhttp3:logging-interceptor:3.5.0"
}

Service

接著先建立一個物件叫做 EInvoiceApiService ,這個物件的目的只是幫我們進行一些 retrofit 通用的初始化,包含基礎路徑以及要使用的 HTTP client 與 logging、JSON converter 元件等,這樣在不同地方要使用 retrofit 的時候就不需重複設定相同的東西了。

Interface

再來就要處理跟 API 定義相關的 code 了,先建立一個叫做 EInvApiInterface 的interface,然後定義 getWinList 這個 function 並加上 Annotation

這樣的定義,看起來是不是既簡潔又容易閱讀呢?

function 裡有三個要定義的地方

  1. @POST(endpoint) 註解是告訴 retrofit 這個 API 將使用 HTTP POST method,裡面的參數則是 API 的路徑,同理如果是 HTTP GET method 的API 則使用 @GET(endpoint)

2. @Query(key) 註解是要求 retrofit 將 function 參數的值轉成 query string (key1=value2&key2=value2…),將要使用的 key 定義放在 Query 第一個參數,預設 retrofit 會幫你作 URLEncode,如果你的參數值已經是 encode 過的,可以寫成 @Query(value= “yourkey”, encoded=true) 避免重複被encode。同理,如果是 form 格式的話,使用的是 @Field

3. 回傳值必須是 retrofitCall interface,型別是你希望 retrofit 幫你轉成 Kotlin 的 data 物件,這裡我們使用之前定義 WinList 物件,這個 data 物件裡欄位的命名已經設定成跟 JSON 的 key 一樣了,retrofit 會透過 GSON Converter 尋找一樣的 key 幫你自動做轉換。

如果有遇到 JSON 參數名稱無法在 Java 下使用,例如在 JSON 中使用數字開頭當作 key 的名字,可以在 data class中使用 @SerializedName 註解,例如

data class MyData {
@SerialzedName("1_key") val firstKey: String
...
}

Runtime

EInvApiInterface 這個 interface function 是要告訴 retrofit 要怎麼處理 API 的資料處理,接著就是要實際建立要求的程式碼。

實際的程式碼就只有兩行:

第一行是透過 createService() 函數取得 retrofit 幫我們產生的 EInvApiInterface 的實做物件。

第二行是提供需要的參數來呼叫 getWinList() 函數,回傳轉成物件的結果。

之後需要增加新的 API 時,只要在 EInvApiInterface 中以同樣的方式定義新的函數即可。

結語

retrofit 是個簡單又實用的 library ,可以大幅減少程式碼,而其標準化的格式讓不同的開發者也能容易看懂以及維護,它還有一些不同的註解函數可以使用,你可以在這裡找到它的參考文件。如果需要參考完整的程式碼可以在 我的 github 找到,記得 checkout retrofit branch。

--

--

No responses yet