Upgrade to Pro — share decks privately, control downloads, hide ads and more …

API 통신, Retrofit 대신 Ktor 어떠신가요

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for Pangmoo Pangmoo
April 03, 2023

API 통신, Retrofit 대신 Ktor 어떠신가요

GDG Korea Android super.init(version=4) 발표 자료 입니다.

Avatar for Pangmoo

Pangmoo

April 03, 2023
Tweet

More Decks by Pangmoo

Other Decks in Programming

Transcript

  1. object KtorClient { val client = HttpClient(CIO) { install(ContentNegotiation) {

    json() } } } object KtorClient { val client = HttpClient(CIO) { install(ContentNegotiation) { json() // for json xml() // for xml cbor() // for cbor protobuf() // for protobuf } } }
  2. RetrofitClient.service.getArticles().enqueue(object : Callback<List<Article>> { override fun onResponse(call: Call<List<Article>>, response: Response<List<Article>>)

    { println("onResponse: ${response.body()}") } override fun onFailure(call: Call<List<Article>>, t: Throwable) { println("onFailure: $t") } })
  3. suspend fun fetchArticlesKtor(): List<Article> = KtorClient .client .get("https://haeyum.dev/articles") .body() suspend

    fun fetchArticlesKtor(): List<Article> = runCatching { KtorClient .client .get("https://haeyum.dev/articles") .body<List<Article>>() }.getOrDefault(emptyList())
  4. Caused by: kotlinx.serialization.MissingFieldException: Field 'id' is required for type with

    serial name 'com.haeyum.ktorretrofit.Article', but it was missing at path: $[0] at path: $[0] at kotlinx.serialization.json.internal.StreamingJsonDeco der.decodeSerializableValue(StreamingJsonDecoder.kt:9 0)
  5. object KtorClient { val client = HttpClient(CIO) { install(ContentNegotiation) {

    json(Json { ignoreUnknownKeys = true coerceInputValues = true prettyPrint = true isLenient = true // ... }) } } }
  6. class VersionInterceptor(private val versionName: String, private val versionCode: String) :

    Interceptor { override fun intercept(chain: Interceptor.Chain): Response = chain.proceed( chain .request() .newBuilder() .addHeader("versionName", versionName) .addHeader("versionCode", versionCode) .build() ) }
  7. val retrofit = Retrofit.Builder() .baseUrl(BASE_URL) .client(provideOkHttpClient(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)) .addConverterFactory(GsonConverterFactory.create()) .build() val

    service = retrofit.create(RetrofitService::class.java) private fun provideOkHttpClient(versionName: String, versionCode: String): OkHttpClient { return OkHttpClient.Builder() .addInterceptor(VersionInterceptor(versionName, versionCode)) .build() }
  8. object KtorClient { val client = HttpClient(CIO) { install(ContentNegotiation) {

    json() } } } object KtorClient { val client = HttpClient(CIO) { install(ContentNegotiation) { json() } defaultRequest { header("versionName", BuildConfig.VERSION_NAME) header("versionCode", BuildConfig.VERSION_CODE) } } }
  9. val mockEngine = MockEngine { request -> val articles =

    listOf( Article("First", "First article"), Article("Second", "This is Mock!"), Article("GDG Korea Android!", "Ktor is awesome!"), ) val headers = headersOf("Content-Type" to listOf(ContentType.Application.Json.toString())) when (request.url.encodedPath) { "/articles" -> respond(Json.encodeToString(articles), headers = headers) else -> respond("Not Found", HttpStatusCode.NotFound) } }
  10. val client = HttpClient(CIO) { install(ContentNegotiation) { json() } defaultRequest

    { header("versionName", BuildConfig.VERSION_NAME) header("versionCode", BuildConfig.VERSION_CODE) } } 실제 서버 사용 시
  11. val client = HttpClient(mockEngine) { install(ContentNegotiation) { json() } defaultRequest

    { header("versionName", BuildConfig.VERSION_NAME) header("versionCode", BuildConfig.VERSION_CODE) } } Mock 사용 시
  12. when (request.url.encodedPath) { "/articles" -> respond(Json.encodeToString(articles), headers = headers) "/article"

    -> { request.url.parameters["id"]?.toIntOrNull()?.let { id -> articles.getOrNull(id)?.let { respond(Json.encodeToString(it), headers = headers) } ?: respond("Not Found", HttpStatusCode.NotFound) } ?: respond("Bad Request", HttpStatusCode.BadRequest) } else -> respond("Not Found", HttpStatusCode.NotFound) } val article = kotlin.runCatching { KtorClient .client .get("/article") { parameter("id", 2) } .body<Article>() }.getOrNull()