JetBrains에서 만들어진 Kotlin을 사용하여 연결된 시스템에서
비동기 서버 및 클라이언트를 구축하기 위한 오픈 소스 프레임 워크
설치, 사용이 간편하여 실행 파이프 라인에 단계를 추가하려는 경우 확장 가능하다.
Coroutine의 비동기 속성으로 인해 여러 요청 수신이 가능하고 MultiPlatform이기도 하다.
즉 서버뿐 아니라 Ktor Client를 써서 Android, iOS, JS에서 마이크로서비스를 사용할 수도 있다.
Ktor Client를 쓰면 요청 생성, 응답 처리 및 인증, Json 직렬화 등과 같은 기능으로 기능을 확장할 수 있다.
구현할 Android는 Client이기 때문에 Client만 알아보았다.
안드로이드에 Ktor 적용
build.gradle (project)
plugins {
id("com.android.application") version "8.1.4" apply false
id("org.jetbrains.kotlin.android") version "1.9.0" apply false
kotlin("plugin.serialization") version "1.9.21" apply false
//kotlin("jvm") version "1.9.21" // 멀티플랫폼이나 다른 플러그인에 serialization 사용할 때 지정
}
build.gradle (app)
dependencies {
//Ktor
implementation("io.ktor:ktor-client-android:<latest-version>")
//JVM, Android 및 Native 플랫폼에서 사용할 수 있는 완전 비동기식 코루틴 기반 엔진
implementation("io.ktor:ktor-client-cio:<latest-version>")
//HTTP Request을 로깅하기 위해 사용
implementation("io.ktor:ktor-client-logging-jvm:<latest-version>")
//직렬화/역직렬화를 위한 ContentNegotiation
implementation("io.ktor:ktor-client-content-negotiation:<latest-version>")
//Serialization json
implementation("io.ktor:ktor-serialization-kotlinx-json:<latest-version>")
//Serialization XML
//implementation("io.ktor:ktor-serialization-kotlinx-xml:<latest-version>")
//Multi Platform Serialization
//implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:<latest-version>")
}
Manifast
<uses-permission android:name="android.permission.INTERNET" />
Basic SetUp Client
기본 Client를 사용하는 방법
Retrofit에서는 함수 형식으로 선언하여 팩토리 패턴으로 클라이언트를 생성하던 것을, Ktor에서는 Scope를 할당하여 DSL 형식으로 작성함으로써 가독성을 높인 것 같음
private const val BASE_URL = "https://"
val ktorClient = HttpClient(CIO){
defaultRequest {
url {
protocol = URLProtocol.HTTPS
host = BASE_URL
}
}
install(ContentNegotiation) {
json() // for json
}
}
object Service {
suspend fun getTodoData(): List<TodoData> {
ktorClient
.get<HttpResponse>(path = "todo")
.body<List<TodoData>>()
}
// Or Client에 defaultRequest 없이도 바로 사용 가능
suspend fun getD() : List<TodoData> {
client.get("url"){
url{
header("HEADER","HEADER.String")
header("HEADER","HEADER.String")
}
}
}
}
//api 호출
val result = Service.getTodoData()
Json 형식의 Request 값을 데이터 객체로 변환하기 위해, Retrofit은 ConverterFactory를 추가하지만
Ktor은 install 함수(플러그인 설치 기능)에 ContentNegotiation를 전달하여 Converter 추가
아래 코드는 네이버 검색 API를 호출하려고 만든 Client와 사용하는 코드이다.
object ApiInfo {
//const val BASE_URL = "https://openapi.naver.com/v1/search/news.json"
const val HOST = "openapi.naver.com"
const val PATH = "/v1/search/news.json"
const val HEADER_ID = "X-Naver-Client-Id"
const val HEADER_SECRET = "X-Naver-Client-Secret"
}
val ktorClient = HttpClient(CIO) {
expectSuccess = true //응답 유효성 검사 true/false
//followRedirects = false //리다이렉트 true/false
//Http 요청에 대해 default value를 세팅하는 역할
defaultRequest {
url {
protocol = URLProtocol.HTTPS
host = HOST //URL Host
path(PATH) //요청 EndPoint
}
//요청 Header 추가 (localProperies 네이버 API id, key)
headers {
header(HEADER_ID, BuildConfig.NAVER_CLIENT_ID)
header(HEADER_SECRET, BuildConfig.NAVER_CLIENT_SECRET)
}
}
// install: client configuration block에 plugin을 가져옴
install(ContentNegotiation) {
json(
Json {
prettyPrint = true // Json string을 읽기 편하게 만들어줌
isLenient = true // 따옴표 규칙 완화
encodeDefaults = true // null 또는 잘못된 값이 들어간 경우 default property value로 대체
ignoreUnknownKeys = true // Field 값이 없는 경우 무시할지 (모델에 없고, json에 있는 경우 해당 key 무시)
}
)
}
//Http 요청 로깅들을 만드는 로깅 역할
install(Logging) {
//logger = Logger.DEFAULT
logger = object : Logger {
override fun log(message: String) {
Log.v("Ktor Logger", message)
}
}
level = LogLevel.ALL
//filter { request -> request.url.host.contains("ktor.io") }
}
//응답의 상태를 기록하는 Observer
install(ResponseObserver) {
onResponse { response -> Log.d("HTTP status: ", "${response.status.value}") }
}
}
class NewsApi(private val client: HttpClient){
suspend fun getNews(query: String) : HttpResponse = client.get{
parameter("query", query)
}
}
class NewRepository{
private val newsApi = NewsApi(ktorClient)
suspend fun getSearchNews(query: String): Flow<List<NewsData>> = flow{
try {
newsApi.getNews(query).run {
if (status.isSuccess()){
//Data Reponse 자동 역직렬화
val response = body<NewsResponse>()
emit(response.items)
}else{
//Api Error 처리
}
}
}catch (e: Exception){
//Network Error 처리
}
}
}
NewRepository는 ViewModel이나 Presenter, Controller에서 getSearchNews()를 호출해 Data를 받아왔다.
전체코드
https://github.com/wo9374/StudyProject/tree/main/NetworkLibrary/Ktor
Ktor
https://daryeou.tistory.com/345
https://medium.com/@ans188/ktor란-무엇일까-750dcc9f77f5
https://velog.io/@dldmswo1209/Compose-UI-Ktor-api-호출
'Android > Library' 카테고리의 다른 글
Fresco (0) | 2022.03.31 |
---|---|
GoogleMap 다중 Marker Clustering, Custom Cluster (0) | 2022.02.21 |
GeoCoding 위도 경도 <-> 주소 변환하기 (4) | 2022.02.20 |
Google Map API 사용 방법 및 예제 (0) | 2022.02.18 |
Epoxy, Epoxy에 Databinding 사용 (RecyclerView 쉽게 사용) (0) | 2022.02.14 |