Skip to content

Express에서 Ktor로 마이그레이션하기

Express에서 Ktor로 마이그레이션하기

이 가이드에서는 애플리케이션 생성과 첫 번째 애플리케이션 작성부터 애플리케이션 기능을 확장하기 위한 미들웨어 생성에 이르기까지, 기본적인 시나리오에서 Express 애플리케이션을 Ktor로 마이그레이션하는 방법을 살펴보겠습니다.

애플리케이션 생성

Express

express-generator 도구를 사용하여 새로운 Express 애플리케이션을 생성할 수 있습니다:

shell
Ktor

Ktor는 애플리케이션 스켈레톤을 생성하는 다음과 같은 방법들을 제공합니다:

  • Ktor Project Generator — 웹 기반 생성기를 사용합니다.

  • Ktor CLI 도구 ktor new 명령어를 통해 커맨드 라인 인터페이스에서 Ktor 프로젝트를 생성합니다:

    shell
  • Yeoman generator — 대화형으로 프로젝트 설정을 구성하고 필요한 플러그인을 선택합니다:

    shell
  • IntelliJ IDEA Ultimate — 내장된 Ktor 프로젝트 마법사를 사용합니다.

자세한 지침은

새로운 Ktor 프로젝트 생성, 열기 및 실행
Learn how to open, run and test a server application with Ktor.
튜토리얼을 참조하세요.

Hello world

이 섹션에서는 GET 요청을 수락하고 미리 정의된 평문 텍스트로 응답하는 가장 간단한 서버 애플리케이션을 만드는 방법을 살펴보겠습니다.

Express

아래 예제는 서버를 시작하고 3000 포트에서 연결을 리스닝하는 Express 애플리케이션을 보여줍니다.

javascript

전체 예제는 1_hello 프로젝트를 참조하세요.

Ktor

Ktor에서는 코드 내에서 서버 파라미터를 구성하고 애플리케이션을 빠르게 실행하기 위해 embeddedServer 함수를 사용할 수 있습니다.

kotlin

전체 예제는 1_hello 프로젝트를 참조하세요.

HOCON 또는 YAML 형식을 사용하는 외부 구성 파일에서 서버 설정을 지정할 수도 있습니다.

위의 Express 애플리케이션은 다음과 같은 Date, X-Powered-By, ETag 응답 헤더를 추가할 수 있습니다:

Ktor에서 각 응답에 기본 ServerDate 헤더를 추가하려면

DefaultHeaders
Required dependencies: io.ktor:%artifact_name%
플러그인을 설치해야 합니다.
ConditionalHeaders
Required dependencies: io.ktor:%artifact_name%
플러그인은 Etag 응답 헤더를 구성하는 데 사용할 수 있습니다.

정적 콘텐츠 제공

이 섹션에서는 Express와 Ktor에서 이미지, CSS 파일, JavaScript 파일과 같은 정적 파일을 제공하는 방법을 살펴보겠습니다. 메인 index.html 페이지와 연결된 에셋들이 포함된 public 폴더가 있다고 가정해 봅시다.

Express

Express에서는 express.static 함수에 폴더 이름을 전달합니다.

javascript

전체 예제는 2_static 프로젝트를 참조하세요.

Ktor

Ktor에서는 staticFiles() 함수를 사용하여 / 경로로 들어오는 모든 요청을 public 물리 폴더로 매핑합니다. 이 함수는 public 폴더의 모든 파일을 재귀적으로 제공할 수 있게 합니다.

kotlin

전체 예제는 2_static 프로젝트를 참조하세요.

정적 콘텐츠를 제공할 때 Express는 다음과 같은 몇 가지 응답 헤더를 추가합니다:

Ktor에서 이러한 헤더를 관리하려면 다음 플러그인들을 설치해야 합니다:

  • Accept-Ranges :

    PartialContent
    Required dependencies: io.ktor:%artifact_name% Server example: download-file, client example: client-download-file-range

  • Cache-Control :

    CachingHeaders
    Required dependencies: io.ktor:%artifact_name%

  • ETagLast-Modified :

    ConditionalHeaders
    Required dependencies: io.ktor:%artifact_name%

라우팅

라우팅
Routing is a core plugin for handling incoming requests in a server application.
은 특정 HTTP 요청 메서드(GET, POST 등)와 경로로 정의된 특정 엔드포인트로 들어오는 요청을 처리할 수 있게 해줍니다. 아래 예제는 / 경로로 들어오는 GETPOST 요청을 처리하는 방법을 보여줍니다.

Express
javascript

전체 예제는 3_router 프로젝트를 참조하세요.

Ktor
kotlin

TIP

POST, PUT, 또는 PATCH 요청의 요청 본문을 수신하는 방법은 요청 수신하기를 참조하세요.

전체 예제는 3_router 프로젝트를 참조하세요.

다음 예제는 경로별로 라우트 핸들러를 그룹화하는 방법을 보여줍니다.

Express

Express에서는 app.route()를 사용하여 라우트 경로에 대해 체이닝 가능한 라우트 핸들러를 만들 수 있습니다.

javascript

전체 예제는 3_router 프로젝트를 참조하세요.

Ktor

Ktor는 route 함수를 제공하며, 여기서 경로를 정의한 다음 해당 경로에 대한 메서드들을 중첩된 함수로 배치할 수 있습니다.

kotlin

전체 예제는 3_router 프로젝트를 참조하세요.

두 프레임워크 모두 단일 파일에서 관련 라우트를 그룹화할 수 있습니다.

Express

Express는 마운트 가능한 라우트 핸들러를 만들기 위해 express.Router 클래스를 제공합니다. 애플리케이션 디렉토리에 birds.js 라우터 파일이 있다고 가정해 봅시다. 이 라우터 모듈은 app.js에서 보여주는 것처럼 애플리케이션에 로드될 수 있습니다:

javascript
javascript

전체 예제는 3_router 프로젝트를 참조하세요.

Ktor

Ktor에서 일반적인 패턴은 Routing 타입에 대한 확장 함수를 사용하여 실제 라우트를 정의하는 것입니다. 아래 샘플(Birds.kt)은 birdsRoutes 확장 함수를 정의합니다. routing 블록 내에서 이 함수를 호출하여 해당 라우트를 애플리케이션(Application.kt)에 포함할 수 있습니다:

kotlin
kotlin

전체 예제는 3_router 프로젝트를 참조하세요.

URL 경로를 문자열로 지정하는 것 외에도, Ktor는

타입 세이프 라우트
The Resources plugin allows you to implement type-safe routing.
를 구현하는 기능을 포함하고 있습니다.

라우트 및 쿼리 파라미터

이 섹션에서는 라우트 및 쿼리 파라미터에 접근하는 방법을 보여줍니다.

라우트(또는 경로) 파라미터는 URL에서 해당 위치에 지정된 값을 캡처하는 데 사용되는 명명된 URL 세그먼트입니다.

Express

Express에서 라우트 파라미터에 접근하려면 Request.params를 사용할 수 있습니다. 예를 들어, 아래 코드 스니펫의 req.parameters["login"]/user/admin 경로에 대해 admin을 반환합니다:

javascript

전체 예제는 4_parameters 프로젝트를 참조하세요.

Ktor

Ktor에서 라우트 파라미터는 {param} 구문을 사용하여 정의됩니다. 라우트 핸들러에서 라우트 파라미터에 접근하려면 call.parameters를 사용할 수 있습니다:

kotlin

전체 예제는 4_parameters 프로젝트를 참조하세요.

아래 표는 쿼리 스트링의 파라미터에 접근하는 방법을 비교합니다.

Express

Express에서 라우트 파라미터에 접근하려면 Request.params를 사용할 수 있습니다. 예를 들어, 아래 코드 스니펫의 req.parameters["login"]/user/admin 경로에 대해 admin을 반환합니다:

javascript

전체 예제는 4_parameters 프로젝트를 참조하세요.

Ktor

Ktor에서 라우트 파라미터는 {param} 구문을 사용하여 정의됩니다. 라우트 핸들러에서 라우트 파라미터에 접근하려면 call.parameters를 사용할 수 있습니다:

kotlin

전체 예제는 4_parameters 프로젝트를 참조하세요.

응답 보내기

이전 섹션들에서 평문 텍스트 콘텐츠로 응답하는 방법을 이미 살펴보았습니다. 이제 JSON, 파일 및 리다이렉션 응답을 보내는 방법을 살펴보겠습니다.

JSON

Express

Express에서 적절한 콘텐츠 타입으로 JSON 응답을 보내려면 res.json 함수를 호출합니다:

javascript

전체 예제는 5_send_response 프로젝트를 참조하세요.

Ktor

Ktor에서는

ContentNegotiation
The ContentNegotiation plugin serves two primary purposes: negotiating media types between the client and server and serializing/deserializing the content in a specific format.
플러그인을 설치하고 JSON 직렬화 도구를 구성해야 합니다:

kotlin

데이터를 JSON으로 직렬화하려면 @Serializable 어노테이션이 있는 데이터 클래스를 만들어야 합니다:

kotlin

그런 다음, call.respond를 사용하여 이 클래스의 객체를 응답으로 보낼 수 있습니다:

kotlin

전체 예제는 5_send_response 프로젝트를 참조하세요.

파일

Express

Express에서 파일로 응답하려면 res.sendFile을 사용합니다:

javascript

전체 예제는 5_send_response 프로젝트를 참조하세요.

Ktor

Ktor는 클라이언트에 파일을 전송하기 위해 call.respondFile 함수를 제공합니다:

kotlin

전체 예제는 5_send_response 프로젝트를 참조하세요.

Express 애플리케이션은 파일로 응답할 때 Accept-Ranges HTTP 응답 헤더를 추가합니다. 서버는 파일 다운로드를 위한 클라이언트의 부분 요청(partial requests) 지원을 알리기 위해 이 헤더를 사용합니다. Ktor에서 부분 요청을 지원하려면

PartialContent
Required dependencies: io.ktor:%artifact_name% Server example: download-file, client example: client-download-file-range
플러그인을 설치해야 합니다.

파일 첨부

Express

res.download 함수는 지정된 파일을 첨부 파일로 전송합니다:

javascript

전체 예제는 5_send_response 프로젝트를 참조하세요.

Ktor

Ktor에서는 파일을 첨부 파일로 전송하기 위해 Content-Disposition 헤더를 수동으로 구성해야 합니다:

kotlin

전체 예제는 5_send_response 프로젝트를 참조하세요.

리다이렉트

Express

Express에서 리다이렉션 응답을 생성하려면 redirect 함수를 호출합니다:

javascript

전체 예제는 5_send_response 프로젝트를 참조하세요.

Ktor

Ktor에서는 respondRedirect를 사용하여 리다이렉션 응답을 보냅니다:

kotlin

전체 예제는 5_send_response 프로젝트를 참조하세요.

템플릿

Express와 Ktor 모두 뷰 작업을 위한 템플릿 엔진을 사용할 수 있습니다.

Express

views 폴더에 다음과 같은 Pug 템플릿이 있다고 가정해 봅시다:

이 템플릿으로 응답하려면 res.render를 호출합니다:

javascript

전체 예제는 6_templates 프로젝트를 참조하세요.

Ktor

Ktor는 FreeMarker, Velocity 등 여러

JVM 템플릿 엔진
Learn how to work with views built with HTML/CSS or JVM template engines.
을 지원합니다. 예를 들어, 애플리케이션 리소스에 배치된 FreeMarker 템플릿으로 응답해야 하는 경우, FreeMarker 플러그인을 설치 및 구성한 다음 call.respond를 사용하여 템플릿을 전송합니다:

kotlin

전체 예제는 6_templates 프로젝트를 참조하세요.

요청 수신하기

이 섹션에서는 다양한 형식의 요청 본문을 수신하는 방법을 보여줍니다.

Raw 텍스트

아래 POST 요청은 서버로 텍스트 데이터를 보냅니다:

http

서버 측에서 이 요청의 본문을 평문 텍스트로 수신하는 방법을 살펴보겠습니다.

Express

Express에서 들어오는 요청 본문을 파싱하려면 body-parser를 추가해야 합니다:

javascript

post 핸들러에서 텍스트 파서(bodyParser.text)를 전달해야 합니다. 요청 본문은 req.body 속성을 통해 사용할 수 있습니다:

javascript

전체 예제는 7_receive_request 프로젝트를 참조하세요.

Ktor

Ktor에서는 call.receiveText를 사용하여 본문을 텍스트로 수신할 수 있습니다:

kotlin

전체 예제는 7_receive_request 프로젝트를 참조하세요.

JSON

이 섹션에서는 JSON 본문을 수신하는 방법을 살펴보겠습니다. 아래 샘플은 본문에 JSON 객체가 포함된 POST 요청을 보여줍니다:

http
Express

Express에서 JSON을 수신하려면 bodyParser.json을 사용합니다:

javascript

전체 예제는 7_receive_request 프로젝트를 참조하세요.

Ktor

Ktor에서는

ContentNegotiation
The ContentNegotiation plugin serves two primary purposes: negotiating media types between the client and server and serializing/deserializing the content in a specific format.
플러그인을 설치하고 Json 직렬화 도구를 구성해야 합니다:

kotlin

수신된 데이터를 객체로 역직렬화하려면 데이터 클래스를 생성해야 합니다:

kotlin

그런 다음, 이 데이터 클래스를 파라미터로 받는 receive 메서드를 사용합니다:

kotlin

전체 예제는 7_receive_request 프로젝트를 참조하세요.

URL-encoded

이제 application/x-www-form-urlencoded 타입을 사용하여 전송된 폼 데이터를 수신하는 방법을 살펴보겠습니다. 아래 코드 스니펫은 폼 데이터가 포함된 샘플 POST 요청을 보여줍니다:

http
Express

평문 텍스트 및 JSON과 마찬가지로, Express에는 body-parser가 필요합니다. 파서 타입을 bodyParser.urlencoded로 설정해야 합니다:

javascript

전체 예제는 7_receive_request 프로젝트를 참조하세요.

Ktor

Ktor에서는 call.receiveParameters 함수를 사용합니다:

kotlin

전체 예제는 7_receive_request 프로젝트를 참조하세요.

Raw 데이터

다음 유스케이스는 바이너리 데이터를 처리하는 것입니다. 아래 요청은 application/octet-stream 타입을 사용하여 PNG 이미지를 서버로 보냅니다:

http
Express

Express에서 바이너리 데이터를 처리하려면 파서 타입을 raw로 설정합니다:

javascript

전체 예제는 7_receive_request 프로젝트를 참조하세요.

Ktor

Ktor는 바이트 시퀀스를 비동기적으로 읽고 쓰기 위해 ByteReadChannelByteWriteChannel을 제공합니다:

kotlin

전체 예제는 7_receive request 프로젝트를 참조하세요.

멀티파트

마지막 섹션에서는 멀티파트(multipart) 본문을 처리하는 방법을 살펴보겠습니다. 아래 POST 요청은 multipart/form-data 타입을 사용하여 설명과 함께 PNG 이미지를 보냅니다:

http
Express

Express에서는 멀티파트 데이터를 파싱하기 위해 별도의 모듈이 필요합니다. 아래 예제에서는 서버에 파일을 업로드하기 위해 multer를 사용합니다:

javascript

전체 예제는 7_receive_request 프로젝트를 참조하세요.

Ktor

Ktor에서 멀티파트 요청의 일부로 전송된 파일을 수신해야 하는 경우, receiveMultipart 함수를 호출한 다음 필요에 따라 각 파트를 순회합니다. 아래 예제에서는 파일을 바이트 스트림으로 수신하기 위해 PartData.FileItem을 사용합니다:

kotlin

전체 예제는 7_receive_request 프로젝트를 참조하세요.

미들웨어 생성

마지막으로 살펴볼 내용은 서버 기능을 확장할 수 있는 미들웨어를 만드는 방법입니다. 아래 예제는 Express와 Ktor를 사용하여 요청 로깅을 구현하는 방법을 보여줍니다.

Express

Express에서 미들웨어는 app.use를 사용하여 애플리케이션에 바인딩된 함수입니다:

javascript

전체 예제는 8_middleware 프로젝트를 참조하세요.

Ktor

Ktor는

커스텀 플러그인
Learn how to create your own custom plugins.
을 사용하여 기능을 확장할 수 있습니다. 아래 코드 예제는 요청 로깅을 구현하기 위해 onCall을 처리하는 방법을 보여줍니다:

kotlin

전체 예제는 8_middleware 프로젝트를 참조하세요.

다음 단계

이 가이드에서 다루지 않은 세션 관리, 권한 부여, 데이터베이스 통합 등 더 많은 유스케이스가 있습니다. 이러한 대부분의 기능에 대해 Ktor는 애플리케이션에 설치하고 필요에 따라 구성할 수 있는 전용 플러그인을 제공합니다. Ktor에 대해 더 자세히 알아보려면 단계별 가이드와 바로 사용할 수 있는 샘플들을 제공하는 학습 페이지(Learn page)를 방문해 보세요.