본문으로 바로가기
반응형
Photo by unsplash

Ktor는 JetBrains에서 만든 server framework입니다. 사실 서버용이라기보다는 각 application 간 connection을 쉽게 만들어주기 위한 framework으로 web applications, HTTP service, mobile application, browser application 등을 모두를 지원합니다.
End-to-End 간 multiplatform application framework을 지원하는 게 최종 목표이며, Kotlin을 기반으로 동작하며 비동기 서비스를 지원하기 위해 내부적으로 coroutine을 사용합니다.
Kotlin이 안드로이드의 기본 언어로 채택되어 많이 보급되어 있는 상황에서 JetBrains이 그들만의 왕국을 건설하려는 야심찬 framework이 아닌가 하는 개인적인 생각을 해봅니다. kotlin과 coroutine의 사용성을 봤을 때 정말 JetBrains 세상이 오지 않을까 조심스럽게 예상해 봅니다.
이번 포스팅에서는 서버용 프로젝트를 생성하는 방법에 대해서 설명합니다. ktor server로 Restful api를 지원하는 서버를 만들고, ktor client로 안드로이드에서 Restful api를 사용하는 server-client의 전체 프로젝트를 생성하고자 합니다.

Ktor 서버 프로젝트의 생성

Ktor 프로젝트를 생성하는 방법은 두가지 입니다. 실제 홈페이지에서는 세 가지인 것처럼 나오지만, editor로 직접 프로젝트를 생성하는 방법을 제외한다면 두 가지 정도입니다. [1]

  • IntelliJ ultimate 이용
  • start.ktor.io 이용

여기서는 start.ktor.io를 이용하여 생성하는 방법에 대해서 설명합니다. IntelliJ를 사용할 경우 유료버전에서만 생성이 가능합니다. 따라서 start.ktor.io를 이용해서 프로젝트를 생성하고 생성된 프로젝트를 IntelliJ Community (무료 버전)에서 사용하도록 하겠습니다.
생성 방법을 보면 spring boot 프로젝트를 만드는것과 유사합니다. spring boot 역시 IntelliJ ultimate에서만 프로젝트를 생성할 수 있습니다. 따라서 intelliJ CE 버전만 사용 가능한 경우 start.spring.io를 통해서 프로젝트를 생성하고, intelliJ CE버전에서 open 하여 사용합니다. 물론 spring boot의 경우 eclipse 기반의 IDE를 추가적으로 제공합니다만, Ktor는 JetBrains에서 만든 framework이니 eclipse를 지원할리 없겠죠?
먼저 start.ktor.io에 접근하여 아래와 같이 세팅합니다.

Project의 이름이나 Website등은 원하는 이름을 넣습니다. build system은 Gradle, Groovy, Maven을 선택할 수 있습니다. spring이었다면 Maven을 선택했겠지만, Android 개발이 익숙한 client 개발자라면 Gradle kotlin이 더 편할 수 있습니다. 개인의 취향??? 에 맞게 선택해 봅니다.
Ktor version은 현재 1.6.7이 최신이나(2022.01.24일 기준), sample project 이므로 2.0.0-beta-1을 선택했습니다. 또한 Web service를 제공할 Engine은 Netty로 선택했습니다. 그 이외에도 아래 그림처럼 Netty, Jetty, CIO, Tomcat을 선택할 수 있습니다.

Configuration in은 HOCON file로 하거나 Code를 선택할 수 있습니다. 전 Code로 선택하겠습니다.

기본 설정이 끝났으므로 Add plugins를 선택합니다.
기본 화면은 아래와 같습니다. SECURITY, ROUTING, HTTP, MONITORING, TEMPLATION, SERIALIZATION등의 section으로 나눠져 필요한 plug in을 선택하여 프로젝트에 추가할 수 있습니다.

저는 예제로 HTTP service (Restful api)를 만들것이므로 여기에 필요한 plugin을 선택해 보도록 하겠습니다.
SECURITY에서 지원하는 인증관련된 부분은 사용하지 않을 예정입니다. 따라서 Routing section으로 넘어가서 Routing, Static Content를 선택합니다. 이는 경로에 따른 routing을 정의하고, 서버에 존재하는 resource를 제공하기 위함입니다.

HTTP 섹션에서는 ContentNegoriation을 추가합니다. 설명을 보면 content를 "Content-Type"과 "Accept" header에 따라서 자동으로 변환한다고 되어 있습니다. JSON을 데이터 포맷으로 주고받을 예정이니 추가합니다.

서버에 요청하는 client의 로깅이 필요합니다. 따라서 MONITORING 섹션에서는 CallLoggin을 추가합니다.

마지막으로 JSON을 좀 더 편하게 변환해줄 library를 선택합니다. SERIALZATION에서 원하는 json parser를 선택합니다. gson을 많이 사용하기는 하지만, JetBrains의 family군인 kotlinx.serialization을 선택하겠습니다.

마지막으로 Generate proejct를 선택하면 프로젝트가 생성되어 zip 파일로 떨어집니다.

생성이 되면 zip 파일이 다운로드되면서 IntelliJ IDEA Ultimate를 쓰라고 나옵니다. 흠... Utlimate는 싸지도 않은 유료이고, 1년 단위로 갱신해서 써야 합니다. 개인은 $199?, 회사라면 $599이었던 듯한데 ktor plugin은 Utilmate 2021.x 이상에서만 설치가 가능하니, 이전 버전이라면 어차피 구매해야 합니다.
하지만 프로젝트 생성만 안될 뿐 IntelliJ CE에서도 생성한 프로젝트를 Open 하여 구현이 가능하므로, CE를 가지고도 충분히 작업이 가능합니다.

IntelliJ에서의 import

InjelliJ CE에서 File -> Open으로 생성된 프로젝트를 추가합니다. 기본 구조는 아래와 같습니다.

Ktor 설정 파일

먼저 gradle 파일부터 확인해 보겠습니다.

안드로이드의 build.gradle과 크게 다르지 않습니다. kotlin은 1.6.10을 사용하고, main class는 "ApplicationKt"로 되어 있습니다. 그리고 plugin에서 선택했던 기본값들이 dependecies에 포함되어 있는 걸 확인할 수 있습니다. 혹시 생성시점에 빼먹은 plugin이나 추가할 게 있다면 직접 추가하면 됩니다.

gradle.properties 파일에는 사용한 버전이 명시되어 있습니다. resources/static에는 서버에서 제공하는 기본 파일들이 들어갑니다. web service를 제공하기 위한 html이 존재할 수도 있고, 서버에서 제공하는 파일 등이 존재하는 위치가 됩니다. (spring boot와 동일한 성격을 띕니다.)

Application.kt

main이 존재하는 시작 부분 파일입니다.

import io.ktor.server.engine.*
import io.ktor.server.netty.*
import com.sample.plugins.*

fun main() {
    embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
        configureRouting()
        configureSerialization()
        configureMonitoring()
    }.start(wait = true)
}

EmbeddedServer를 사용하여 구동되며 프로젝트 생성 시 선택했던 Netty 엔진을 이용하는 것으로 되어 있습니다. main 옆에 존재하는 >를 눌러서 바로 실행시켜볼 수 있습니다.

HOCON 설정 파일 사용 시
만약 프로젝트 생성 시 Configuration을 "code"가 아닌 "HOCON"을 선택했다면 Application.kt의 파일 내용이 달라집니다.

아래와 같이 표기되며, 설정 파일은 하기 경로에 위치합니다. (application.conf)

만약 intelliJ CE버전에서 해당 파일이 자동 생성되지 않았다면 아래의 내용대로 application.conf파일을 추가합니다.

ktor {
    deployment {
        port = 8080
        port = ${?PORT}
    }
    application {
        modules = [ com.sample.ApplicationKt.module ]
    }
}

실제로 파일을 열어보면 상단에". conf 파일은 기타 JetBrains IDE에서 지원합니다"라는 문구가 뜹니다. 포트번호는 8080으로 되어 있으나 여기서 원하는 포트번호로 변경이 가능합니다.

Application.module()

main() 함수에 보면 아래와 같이 세 개의 함수를 호출하도록 되어 있습니다.

이 함수들은 하기 경로에서 각각 extention function을 이용하여 구현되어 있습니다.

Monitoring
이중 configureMonitoring() 함수는 서버에 접속되는 client 로그를 남기기 위해서 plugin에서 추가했던 CallLogging을 설정합니다. Application에서 바로 사용할 수 있도록 extention function을 이용하여 아래와 같이 작성되어 있습니다.

Monitoring.kt

CallLogging을 추가하고, level은 INFO, "/"로 시작하는 요청만 로깅하도록 filtering 되어 있습니다.
Routing

Rounting.kt

configureRouting()은 routing에 관련된 내용을 추가합니다. 기본 주소로 접속 시 "Hello world"를 화면에 출력하도록 되어 있습니다.

static은 서버의 resrouce에 접속하기 위한 설정입니다. 추후 RestfulApi 서버 생성 포스팅에서 좀 더 자세하게 다룹니다.
Serialzation

Serialization.kt

ContentNegoriation을 json으로 설정합니다. 즉 데이터를 json 포맷으로 주고받겠다는 의미이며, 이때 사용할 converter로는 plugin으로 설치했던 kotlinx.serialization이 됩니다.
그리고 여기에 test를 위한 get방식의 routing을 추가되어 있습니다. "/json/kotlinx-serialization"의 경로로 접근하면 "hello: world"의 기본 json을 응답으로 주겠다는 의미입니다. 여기서는 간단하게 json을 생성하기 위해 map 형태로 작성이 가능하다는 걸 보여줍니다.

마치면서

이로써 기본적인 ktor 서버 생성이 끝났습니다. 위에서 언급된 코드들은 대부분 기본적으로 생성되는 코드들입니다. 따라서 간단한 서버 프로그램 작성 시 유용하게 사용될 수 있으며 run을 누르면 빠른 속도로 서버가 launching 되는 걸 볼 수 있습니다.
개인적으로는 spring boot의 kotlin 버전이라는 생각이 들었습니다. spring boot는 java를 이용하여 쉽게 만들 수 있지만 java와 99%? 호환성을 갖는 kotlin을 사용해서도 만들수 있습니다. 언어적으로는 두 개의 언어가 호환성이 높다고는 하지만 spring에서 제공하는 여러 library들은 kotlin에 대한 공식적인 지원을 하지 않기 때문에 kotlin으로 spring boot를 작성 시 조금씩은 다른 점이 발생합니다. (예제 그대로 java ->kotlin으로만 변경했을 때도 알게 모르게 에러가 많이 발생합니다.)
아예 kotlin base로 시작하는 Ktor의 경우 kotlin만의 장점을 많이 누릴 수 있습니다. 좀 던 간략화된 언어적 표현이라던가, 위에서 사용했듯이 extention function을 이용하여 쉽게 기능을 추가할 수 있으며, coroutine을 사용하여 sequential 하고 강력한 비동기 처리를 구현할 수 있습니다.
다음 포스팅에는 여기서 기본으로 생성한 서버 프로젝트를 기반으로 HTTP service (Restful Api) 서버를 만듭니다. 오히려 이 포스팅보다 내용이 적고 간단할 수 있으며, client 개발자가 쉽게 서버를 개발할 수 있는 지름길로 보입니다.

References

[1] https://ktor.io/create/
[2] https://ktor.io/docs/creating-http-apis.html

반응형