Ktor

HEETAE HEO·2023년 4월 15일
0
post-thumbnail

Ktor - Client
: Kotlin으로 작성된 비동기식 웹 프레임워크로 Android에서는 백엔드 서버와 클라이언트 사이의 네트워킹 라이브버리로 사용할 수 있습니다. Retrofit과 마찬가지로 헤더 추가, 다양한 직렬화 라이브러리 선택 등과 같은 기능을 통해 API 통신이 가능합니다.

(Android 개발자 입장에서)

Ktor은 Retrofit과 마찬가지로 네트워킹을 수행해주는 라이브러리 입니다.

그렇다면 Ktor을 써야할까? Retrofit이 있는데

Retrofit : OkHttp를 사용하여 HTTP 요청을 처리합니다. OkHttp는 Square에서 개발한 안드로이드 및 자바 플랫폼을 위한 오픈소스 Http 클라이언트 입니다. OkHttp의 주요 특징은 다음과 같습니다.

  1. 신뢰성: OkHttp는 모든 네트워크 작업에서 타임아웃과 같은 오류에 대비하며, 안정적인 동작을 보장합니다.

2.성능: OkHttp는 HTTP/2 지원, 커넥션 풀링 및 인코딩 방식 등의 기술을 사용하여 빠른 성능을 제공합니다.

3.편리한 API: OkHttp는 간결하고 이해하기 쉬운 API를 제공하여 개발자가 쉽게 사용할 수 있습니다.

4.인터셉터: OkHttp는 인터셉터를 사용하여 요청 및 응답을 가로채거나 수정할 수 있어 확장성을 제공합니다.

Ktor : HttpClient를 사용하여 HTTP 요청을 처리하며 여러 엔진 중 하나를 선택하여 사용할 수 있습니다.

1.플랫폼 독립성: 여러 엔진 중 하나를 선택하여 사용할 수 있으므로, 플랫폼에 독립적으로 동작합니다.

2.코루틴 지원: Ktor는 코틀린의 코루틴을 지원하며, 비동기 작업을 쉽게 처리할 수 있도록 도와줍니다.

3.모듈화 및 확장성: Ktor는 기능을 설치하여 구성하거나 제거할 수 있는 모듈화된 구조를 사용하여, 확장성과 유연성을 제공합니다.

4.DSL 스타일: Ktor는 코틀린의 DSL 스타일 구성을 사용하여 직관적이고 간결한 코드 작성을 가능하게 합니다.

DSL의 예시 입니다.

val client = HttpClient({
        install(JsonFeature) {
            serializer = KotlinxSerializer()
        }
        install(Logging) {
            logger = Logger.DEFAULT
            level = LogLevel.ALL
        }
    }

Ktor Client에 사용되는 주요 엔진

Apache: Apache HTTP 클라이언트를 기반으로 하는 엔진으로, 자바 플랫폼에서 사용할 수 있습니다.

장점 : 검증된 안전성, 사용자 지정 설정 및 기능을 활용할 수 있는 다양한 확장성을 제공합니다.

단점 : 자바 기반 프로젝트에만 사용할 수 있으며, 코루틴을 지원하지 않음

사용 : 자바 플랫폼에서 안정성과 확장성이 필요한 경우 사용할 수 있는 엔진

OkHttp: Retrofit과 동일한 OkHttp 클라이언트를 기반으로 하는 엔진으로, 안드로이드 및 자바 플랫폼에서 사용할 수 있습니다.

장점 : 안정적, 빠른 성능, HTTP/2 지원, 커넥션 풀링 및 인코딩 방식 및 인터셉터를 사용하여 요청 및 응답을 가로채거나 수정 가능

단점 : 자바 및 안드로이드 플랫폼에서만 사용할 수 있습니다.

사용 : 안정성과 성능이 중요한 경우 사용할 수 있는 엔진입니다. Retrofit과 동일한 OkHttp 클라이언트를 사용하므로, 비슷한 특징을 지닙니다.

Android: 안드로이드 플랫폼에 최적화된 HTTP 클라이언트 엔진입니다. (내부적으로 OKHttp 라이브러리를 사용함)

장점 : 안드로이드 플랫폼 전용으로 만들어진 엔진으로 httpURLConnection 기반으로 만들어짐

단점 : 안드로이드 플랫폼에서만 사용가능 코루틴 지원이 제한적

사용 : 안드로이드 전용 프로젝트에 적합한 엔진입니다. 플랫폼 특성을 최대한 활용할 수 있다.

CIO: Ktor에서 제공하는 순수 코틀린 멀티플랫폼 엔진입니다. 이 엔진은 JVM, 안드로이드, iOS 및 JavaScript 플랫폼에서 사용할 수 있습니다.

장점 : 순수 코틀린 기반의 멀티플랫폼 엔진입니다. JVM, 안드로이드, ios 및 JavaScript 플랫폼에서 사용할 수 있습니다. 코루틴을 지원하여 비동기 작업을 쉽게 처리가능 합니다.

단점 : 성능 및 안정성 측면에서 다른 라이브러리 만큼 검증되지 않음

사용 : 멀티플랫폼 프로젝트에 적합한 엔진 및 코루틴 지원과 플랫폼 독립성을 원할 경우 사용가능

Ktor과 Retrofit에 대한 특징을 잠깐 알아봤습니다. 이제 두 가지의 네트워킹 라이브러리의 차이를 알아보겠습니다.

컴파일러 차이

Retrofit은 Android 에서 네트워킹 라이브러리를 사용하려는 경우 유용합니다. 다음과 같은 문제가 있습니다.

Rtrofit2는 Kotlin/Native 컴파일러를 지원하지 않는다!

Kotlin의 컴파일러가 지원하는 플랫폼 3가지

  1. Kotlin/JVM: JVM을 타켓으로 컴파일, Android 앱 빌드 시 해다 플랫폼을 타겟으로 합니다.

  2. Kotlin/js: ES5을 대상으로 한 JavaScript로 변환하는 기능 제공

  3. Kotlin/Native: Virtual Machine 없이 구동할 수 있도록 네이티브 바이너리로 컴파일합니다. Kotlin 컴파일러용 LLVM(Low Level Virtual Machine) 기반의 백엔드와 Kotlin standard 라이브러리를 가진 native 구현이 포함됩니다.

LLVM : 재사용 가능한 컴파일러이자, 툴체인 기술의 집합체 이며 바이너리로 내 코드를 컴파일하는데 사용되는 라이브러리입니다.

여기서 Rtrofit2은 Kotlin/Jvm을 타겟으로 하는 라이브러리에 의존하고 있기 때문에 여러 개의 플랫폼에서는 사용이 불가능 한 것입니다.

반면 Ktor을 사용하면 KMM이라는 멀티플랫폼( 대표 예 : Android,ios)를 다 구현이 가능한 것입니다.

인스턴스 생성의 간소화(모듈화)??

Retrofit2

object ApiClient {
    private const val BASE_URL = "Base_url"
    private val retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
}

: Retrofit2에서 서버와 REST API 통신을 진행하기 위해선 제공하는 함수를 통해 Builder를 준비하고, 받아온 Request 결과 값(JSON,Protobuf)을 Service Interface의 구현체으로 변환하여 데이터로 사용할 수 있습니다.

Ktor

install(JsonFeature){
		serializer = KotlinSerializer(
			kotlinx.serialization.json.Json {
				prettyPrint = true
				isLenient = true
        ignoreUnknownKeys = true
				}
		 )
	}
    
    install(HttpTimeout) {
		requestTimeoutMillis = 30000L // requestTime 제한시간 30초 
    	connectTimeoutMillis = 30000L // connectTime 제한시간 30초 
    	socketTimeoutMillis = 30000L // socketTime 제한시간 30초
	}
    
    defaultRequest {
            header(...)
         	header(...)
            header(...)
            header(...)
        }

Ktor 역시 비슷한 과정을 수행하지만 약간의 차이점이 있습니다. Json 형식의 Request 값을 데이터 객체로 변환하기 위해 install() 함수에 ContentNegotiation를 전달하여 converter를 추가해주고 TimeOut을 걸어줍니다.

멀티파트 요청 차이

Retrofit2에서 Image 데이터를 전송하기 위해 다음과 같이 구현합니다.

interface ImageApi {
    @Multipart
    @POST("end_Point")
    suspend fun uploadImage(
        @Part image: MultipartBody.Part
    ): ResponseBody

    companion object {
        val instance by lazy {
            Retrofit.Builder()
                .baseUrl("https://example.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build()
                .create(ImageApi::class.java)
        }
    }
}

interface ImageRepository {
    suspend fun uploadImage(file: File): ResponseBody?
}

class ImageRepositoryImpl(
    private val imageApi: ImageApi
) : ImageRepository {
    override suspend fun uploadImage(file: File): ResponseBody? {
        return try {
            val requestFile = file.asRequestBody("image/*".toMediaTypeOrNull())
            val imagePart = MultipartBody.Part.createFormData("image", file.name, requestFile)
            imageApi.uploadImage(imagePart)
        } catch (e: Exception) {
            // 예외 처리
            null
        }
    }
}

반면 Ktor의경우에는 다음과 같이 구현하게 됩니다.


suspend fun uploadImage(file: File) {
    val client = HttpClient {
        install(Logging) {
            logger = Logger.DEFAULT
            level = LogLevel.INFO
        }
    }

    val response: HttpResponse = client.submitFormWithBinaryData(
        url = "https://your-api-endpoint.com/upload",
        formData = formData {
            append("image", file.readBytes(), Headers.build {
                append(HttpHeaders.ContentDisposition, 
                       "filename=${file.name}")
            })
        }
    )

}

코루틴 지원 차이

Ktor-client는 기본적으로 코루틴을 사용하여 동작합니다. Ktor의 모든 기능과 구성 요소는 코루틴 기반으로 설계되어 있어, 동시성 제어 및 비동기 작업을 코루틴을 통해 자연스럽게 처리할 수 있습니다. 반면 Retrofit은 원래 콜백 기반의 비동기 처리를 사용하였으나, 코루틴을 지원하게 되면서 suspend 함수를 사용하여 API 선언을 해주고 호출 시 코루틴 스코프에서 실행되도록 합니다.

그렇다면 Ktor, Retrofit 둘 다 코루틴을 사용할 수 있는데 코루틴 지원이라는게 장점이 맞나요???

장점으로 볼 수 있는 이유는 모든 구성요소와 기능이 코루틴을 기반으로 설계되었다는 것! 입니다.

Ktor

	val client = HttpClient()
    val url = "https://example.com"
 

    runBlocking {
        val response: ApiResponse = client.get(url)
        println(response)
    }

Retrofit

  interface ApiService {
    @GET("/example")
    suspend fun getPost(): Res 
  }
  	runBlocking {
        val response = apiService.getPost()
        println(response)
    }

모든 구성요소가 코루틴 기반으로 설계가 된 Ktor의 경우에는 get 함수 자체가 suspend 함수이기 때문에 코루틴 스코프 내에서 호출이 됩니다. 반면 Retrofit은 API를 정의하는 interface를 선언하고 해당 함수를 suspend로 선언해 코루틴 스코프 내에서 선언된 suspend 함수를 호출하는 방식입니다.

다음은 인터셉터를 생성하는 부분의 차이점을 보겠습니다.

Ktor

	val client = HttpClient {
        install(HttpTimeout) {
           // TimeOut 설정 
        }

        install(ResponseObserver) {
            onResponse { response ->
                // 인터셉터에서 할 동작 정의
            }
        }

		install(Logging) {
            level = LogLevel.HEADERS

		        }
			  }

Retrofit

class LoggingInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val response = chain.proceed(request)
        return response
		// 인터셉터에서 할 동작 정의 
    }
}

val okHttpClient = OkHttpClient.Builder()
        .addInterceptor(LoggingInterceptor())
        .addInterceptor(loggingInterceptor)
        .build()

    val retrofit = Retrofit.Builder()
        .baseUrl("https://example.com")
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create())
        .build() 

인터셉터 부분을 보면 확실한 차이가 존재합니다. OkHttp 클라이언트에서는 인터셉터를 addInterceptor를 통해 추가 구성합니다. OkHttp 인터셉터는 콜백 기반으로 작동하며, 코루틴과는 별개로 동작합니다. 반면 Ktor은 코루틴을 기반으로 하는 인터셉터와 기타 확장 기능을 제공하여 동시성 제어를 더욱 쉽게 처리할 수 있도록 해줍니다.

profile
Android 개발 잘하고 싶어요!!!

0개의 댓글