Day 10:让你见识我的一小部分力量,Ktor的网路请求

Keyword: Ktor, Suspend Function
到Day11使用Ktor进行网路请求并且显示在Android画面的Code放在
KMMDay11


Ktor是十分强大的网路框架,可以帮助开发者迅速进行网路开发,我们借助其中一小部分功能,来进行网路Api的请求.

今天的范例Api ,我们使用 Cafe Nomad:咖啡厅游牧民的Api,我常在咖啡厅工作,偶尔也会查一下这个网站.非常感谢.

https://cafenomad.tw/api/v1.2/cafes/{cityName}

网路请求的回传形式如下,还蛮详细的.

[{
    "id": "000703fe-cf8a-43c8-bd83-c90cfd61915f",
    "name": "蜂巢咖啡",
    "city": "taipei",
    "wifi": 0,
    "seat": 4.5,
    "quiet": 3,
    "tasty": 5,
    "cheap": 4,
    "music": 4,
    "url": "https://www.facebook.com/honeycombcafe2016/",
    "address": "新北市永和区永贞路214号",
    "latitude": "25.00409680",
    "longitude": "121.51528650",
    "limited_time": "no",
    "socket": "no",
    "standing_desk": "yes",
    "mrt": "永安市场站",
    "open_time": "双周四公休,有变更另外公告"
  }
]

详细文件可以到以下

https://cafenomad.tw/developers/docs/v1.2

使用Ktor

由於我们这次的Api资料是要双平台一起共用的,也没有根据平台不同而要特别处理的逻辑,也因此程序码实作区块放在shared模组中的commonMain中即可.
为了未来更好阅读和修改,我推荐在shared底下建立以下结构

model/remote/ktor/

以後会将Ktor所用到的物件放在这里

https://github.com/officeyuli/itHome2021/raw/main/day10/ktor%20path.jpg

首先先根据需要的回传值建立一个对应的物件,这次的范例不会把整个物件接起来,挑几个值比较重要的就好了,需要其他的值可以自己加入.

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable//要注意不要import错了

@Serializable
data class CafeResponseItem(
    val id: String, //参数的名称即是对应的json key
    val address: String, 
    val name: String,
    @SerialName("city") val cityName:String //如果json key跟参数不同,可以使用SerialName
)

然後建立一个interface,加入api path

interface CafeApi {
    suspend fun fetchCafeFromApi(city:String): List<CafeResponseItem>
}

注意这边是suspend function,要跑在coroutine环境中.

然後再建立一个此interface的实作CafeApiImpl物件

先建立一个Ktor的HttpClient物件,HttpClient会负责管理连线,我们会根据需求调整HttpClient设定.

private val client = HttpClient {}

首先是JsonFeature的设定,这边可以设定要用什麽解析器来进行Response的解析,例如常用的Gson等等.

这边使用我们昨天引入的Kotlinx-Serializer解析器

install(JsonFeature){
    serializer = KotlinxSerializer(kotlinx.serialization.json.Json { ignoreUnknownKeys = true })
	//由於我们没有把每个key值接起来,所以还要额外设定忽略未知的key,ignoreUnknownKeys
    //注意前面的Json要使用Kotlinx-Serializer内的,有需多同名的Json,要小心不要用错了.
}

然後是Logging的设定,目前就先简单的印出来看看数据正确,我们之後会根据各平台来实作不同的Log

LogLevel也可以根据自己需要的程度调整

install(Logging){
    logger = object : Logger{
        override fun log(message: String) {
             println(" CafeApiImpl log: $message" )
            }
      }
     level = LogLevel.INFO
 }

最後是网路请求timeout设定

install(HttpTimeout){
            val timeout = 20000L
            connectTimeoutMillis = timeout
            requestTimeoutMillis = timeout
            socketTimeoutMillis = timeout
        }

最後整个HttpClient设定就会像这样

private val client = HttpClient {
        install(JsonFeature){
            serializer = KotlinxSerializer(kotlinx.serialization.json.Json { ignoreUnknownKeys = true })
        }
        install(Logging){
            logger = object : Logger{
                override fun log(message: String) {
                    println(" CafeApiImpl log: $message" )
                }
            }
            level = LogLevel.INFO
        }
        install(HttpTimeout){
            val timeout = 50000L
            connectTimeoutMillis = timeout
            requestTimeoutMillis = timeout
            socketTimeoutMillis = timeout
        }
    }

有了HttpClient後,就可以利用HttpClient发起网路请求,在使用HttpClient时,需要传入一个HttpRequestBuilder

override suspend fun fetchCafeFromApi(city :String): List<CafeResponseItem>{
        return client.get<List<CafeResponseItem>>{
            getCafeListHttpBuilder(city)
        }
    }

cafeListHttpBuilder的内容如下,在HttpRequestBuilder中不只url,还能设定headers,body等等

private fun HttpRequestBuilder.getCafeListHttpBuilder(path: String) {
        url{
            if(path.isNotEmpty()){
                takeFrom("https://cafenomad.tw/api/v1.2/cafes/$path")
            }else{
                takeFrom("https://cafenomad.tw/api/v1.2/cafes/")
            }
        }
    }

这样我们就完成了网路请求流程,明天会在Android上来显示的网路请求的结果


<<:  Day61 (Vue)

>>:  [Day 14] 简单的单元测试实作(八)-修改成API来呼叫

Day 29:Playbook 的模组化

前天我提到了希望可以研究一下如何做 playbook 的模组化,今天就来整理一下有哪些方式可以帮助我...

Day27-useMemo

前言 前两天我们学习了React性能优化 memo 组件记忆 useCallback 函式参考记忆 ...

过渡到特殊教育需求教学

要考虑的主要和最重要的事情是熟悉不同特殊教育需求的行话和定义。成功的教学要求教师了解每个学生及其个人...

安全工程101

系统工程是一门应用知识来创建或获取一个系统的学科,该系统由相互关联的元素组成,这些元素在整个系统开...

Day_26: 让 Vite 来开启你的Vue之 跌入深坑_ 我该用 reactive 还是 ref

Hi Dai Gei Ho~ 我是 Winnie ~ 在接下来最後三篇文章中,我们将要进入 Vue跌...