iT邦幫忙

2022 iThome 鐵人賽

DAY 20
0
Mobile Development

Kotlin 全面啟動 系列 第 20

[Kotlin 全面啟動] Ktor Client III

  • 分享至 

  • xImage
  •  

今天來介紹 Ktor Client 的最後一篇,我們該如何使用之前所介紹的 serialization 讓 API 回傳直接變成我們想要的物件格式!

由於需要 kotlinx.serialization 的相關知識,如果大家還沒看過的話可以參考一下前幾天的文章:
https://ithelp.ithome.com.tw/articles/10302034

ContentNegotiation

ContentNegotiation 是 Ktor 的一個 plugin,主要是讓我們可以使用各個不一樣的 serialization 來把 API 轉換我們想要的物件,所以第一步我們要把這個 dependency 加到我們的專案中:

implementation("io.ktor:ktor-client-content-negotiation:2.1.0")

還記得什麼是 plugin 嗎?Ktor core 的設計主要是提供一個框架,大部分功能都是透過 plugin 的方式完成,而 Ktor 的 plugin 也是一個 gradle 的 dependency,並不是 gradle 的 plugin 喔!

跟 Ktor core 一樣,我們除了增加 ContentNegotiation 之外,也需要告訴 ContentNegotiation 我們想要用什麼方式來做 serialization,目前除了 json 之外共有以下幾種:

// json
implementation("io.ktor:ktor-serialization-kotlinx-json:2.1.0")
// xml
implementation("io.ktor:ktor-serialization-kotlinx-xml:2.1.0")
// cbor
implementation("io.ktor:ktor-serialization-kotlinx-cbor:2.1.0")

Install

使用也跟之前的 convention 蠻類似的,畢竟 ContentNegotiation 也是一個 plugin,所以只要在 HttpClient 的 lambda block 呼叫 install 就可以了:

val client = HttpClient(CIO) {
    install(ContentNegotiation)
}

但我們還需要指定 ContentNegotiation 所指定的 serialization 是 json 而不是其他方法,所以在 install 這個 block 繼續新增我們的參數如下:

val client = HttpClient(CIO) {
    install(ContentNegotiation) {
        json()
    }
}

json 這個 block 當然也可以繼續做些設定,最常見的就是以下這三個屬性:

val client = HttpClient(CIO) {
    install(ContentNegotiation) {
        json(Json {
            prettyPrint = true
            isLenient = true
            ignoreUnknownKeys = true
        })
    }
}

參數的意義如下:

  • prettyPrint:print 的時候會有比較好的 format,預設為 false
  • isLenient:讓 parse 的時候不會因為資料格式不對造成錯誤,比如說 string 沒有用 "" 包起來等,這個可以先跟 backend 溝通一下是否有這個需求,有需要再加。
  • ignoreUnknownKeys:轉換時如果有無法 mapping 的 key 的時候,要不要視為錯誤,通常會設成 true 比較好做向下相容,或是可以把物件定義為比 API 回傳還要更小的結構,但也可以依據你的需求調整。

Example

接下來我們還是以之前所說的 https://api.github.com/users/<USERNAME> 為例,以下是一個回傳的結果:

{
  login: "Jintin",
  id: 3413874,
  node_id: "MDQ6VXNlcjM0MTM4NzQ=",
  avatar_url: "https://avatars.githubusercontent.com/u/3413874?v=4",
  gravatar_id: "",
  url: "https://api.github.com/users/Jintin",
  html_url: "https://github.com/Jintin",
  followers_url: "https://api.github.com/users/Jintin/followers",
  following_url: "https://api.github.com/users/Jintin/following{/other_user}",
  gists_url: "https://api.github.com/users/Jintin/gists{/gist_id}",
  starred_url: "https://api.github.com/users/Jintin/starred{/owner}{/repo}",
  subscriptions_url: "https://api.github.com/users/Jintin/subscriptions",
  organizations_url: "https://api.github.com/users/Jintin/orgs",
  repos_url: "https://api.github.com/users/Jintin/repos",
  events_url: "https://api.github.com/users/Jintin/events{/privacy}",
  received_events_url: "https://api.github.com/users/Jintin/received_events",
  type: "User",
  site_admin: false,
  name: "Jintin",
  company: null,
  blog: "https://www.linkedin.com/in/jintin",
  location: "Taipei, Taiwan",
  email: null,
  hireable: true,
  bio: "Android GDE, husband and dad.
  Love to build interesting things to make life easier.",
  twitter_username: "JintinLin",
  public_repos: 44,
  public_gists: 2,
  followers: 170,
  following: 6,
  created_at: "2013-01-29T06:30:00Z",
  updated_at: "2022-08-15T09:29:11Z"
}

因為蠻多參數對我們目前都不太重要,我們可以先簡單定義如下的 User class:

@Serializable
data class User(
    val login: String,
    val id: Long,
    @SerialName("avatar_url")
    val avatarUrl: String,
)

如果你的 config 沒有 ignoreUnknownKeys 的話,而有 key 無法對應的話會直接報錯喔!

一切都完成以後,使用就非常簡單了,只要直接宣告我們要的型別是 User 就可以囉!

val user: User = client.get("https://api.github.com/users/Jintin").body()

To Be Continued

這邊埋一下伏筆,之後我們介紹 KSP 的時候,其中一個範例將會是使用 KSP 讓 Ktor 的使用變得像 Retrofit 一樣的簡單喔,敬請持續關注!


上一篇
[Kotlin 全面啟動] Ktor Client II
下一篇
[Kotlin 全面啟動] Ktor Server
系列文
Kotlin 全面啟動 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言