Docs Menu
Docs Home
/ /

Ktor 및 MongoDB Atlas 사용하여 API 만들기

Ktor는 최신 웹 애플리케이션 및 API 빌드를 위해 설계된 코틀린(Kotlin) 기반 비동기 웹 프레임워크 입니다. 코틀린 (Kotlin) ) 코루틴을 사용한 비동기 프로그래밍을 강력하게 지원 합니다.

이 튜토리얼에서는 Ktor, 코틀린 (Kotlin) 운전자 및 MongoDB Atlas 사용하여 실행 가능한 API 설정하다 방법을 학습 봅니다.

1

이 튜토리얼을 시작하기 전에 다음 사항이 있는지 확인하세요.

  • 클러스터 가 있는 MongoDB Atlas 계정. 지침을 보려면 시작하기 가이드 참조하세요.

  • IntelliJ IDEA.

2

Ktor 프로젝트 생성기를 사용하여 새 Ktor 프로젝트 생성합니다.com.mongodb.fitness-tracker 텍스트 입력 필드 사용하여 프로젝트 아티팩트의 이름을 로 지정합니다.Configure 버튼을 클릭하고 다음 옵션을 지정합니다.

  • 빌드 시스템: Gradle 코틀린 (Kotlin)

  • 엔진: 톰캣

  • 구성: HOCON 파일

새 Ktor 프로젝트 페이지의 Plugins 메뉴를 사용하여 프로젝트 에 다음 플러그인을 추가합니다.

  • 콘텐츠 협상: 클라이언트 와 서버 간의 미디어 유형 협상

  • GSON: 직렬화 및 역직렬화 지원 제공

  • 라우팅: 수신 요청 관리

  • Swagger: API 문서 생성

Generate Project 버튼을 클릭하여 새 Ktor 프로젝트 포함된 ZIP 파일 다운로드 .

다운로드한 파일 의 압축을 풀고 프로젝트 디렉토리 의 루트 디렉토리 에서 build.gradle.kts 파일 엽니다. plugins 차단 에 다음 플러그인을 추가합니다.

plugins {
kotlin("jvm") version "1.9.22"
id("io.ktor.plugin") version "2.3.7"
id("org.jetbrains.kotlin.plugin.serialization") version "1.9.22"
}

동일한 파일 의 dependencies 차단 에 다음 종속성을 추가합니다.

dependencies {
implementation("io.ktor:ktor-server-core-jvm")
implementation("io.ktor:ktor-server-swagger-jvm")
implementation("io.ktor:ktor-server-content-negotiation-jvm")
implementation("io.ktor:ktor-serialization-gson-jvm")
implementation("io.ktor:ktor-server-tomcat-jvm")
implementation("ch.qos.logback:logback-classic:$logback_version")
implementation("io.ktor:ktor-server-config-yaml:2.3.8")
// MongoDB
implementation("org.mongodb:mongodb-driver-kotlin-coroutine:5.6.1")
// Koin dependency injection
implementation("io.insert-koin:koin-ktor:3.5.3")
implementation("io.insert-koin:koin-logger-slf4j:3.5.3")
// Client
implementation("io.ktor:ktor-client-core:$ktor_version")
implementation("io.ktor:ktor-client-cio:$ktor_version")
}
3

src/main/kotlin 디렉토리 아래에 다음 세 개의 패키지를 만듭니다.

  • application

  • domain

  • infrastructure

domain 패키지 내에서 entity라는 새 하위 패키지를 만든 다음 entity 내에 Fitness.kt라는 파일 만듭니다. 다음 코드를 파일 에 복사합니다.

package com.mongodb.domain.entity
import com.mongodb.application.response.FitnessResponse
import org.bson.codecs.pojo.annotations.BsonId
import org.bson.types.ObjectId
data class Fitness(
@BsonId
val id: ObjectId,
val exerciseType: String,
val notes: String,
val details: FitnessDetails
){
fun toResponse() = FitnessResponse(
id = id.toString(),
exerciseType = exerciseType,
notes = notes,
details = details
)
}
data class FitnessDetails(
val durationMinutes: Int,
val distance: Double,
val caloriesBurned: Int
)

앞의 코드의 toResponse() 메서드는 아직 FitnessResponse 클래스를 생성하지 않았기 때문에 오류가 발생합니다. application/request 패키지 아래에 requestresponse 패키지를 생성하고 해당 패키지 에 FitnessRequest.ktFitnessResponse.kt 라는 파일 두 개를 생성합니다.

다음 코드를 FitnessRequest.kt 파일 에 복사합니다.

package com.mongodb.application.response
import com.mongodb.domain.entity.FitnessDetails
data class FitnessResponse(
val id: String,
val exerciseType: String,
val notes: String,
val details: FitnessDetails
)

다음 코드를 FitnessResponse.kt 파일 에 복사합니다.

package com.mongodb.application.response
import com.mongodb.domain.entity.FitnessDetails
data class FitnessResponse(
val id: String,
val exerciseType: String,
val notes: String,
val details: FitnessDetails
)

domain 패키지 아래에 ports 패키지 만들고 ports 패키지 에 FitnessRepository.kt 라는 파일 만듭니다. 이 파일 데이터베이스 와 통신할 인터페이스를 나타냅니다. 다음 코드를 FitnessRepository.kt 파일 에 복사합니다.

package com.mongodb.domain.ports
import com.mongodb.domain.entity.Fitness
import org.bson.BsonValue
import org.bson.types.ObjectId
interface FitnessRepository {
suspend fun insertOne(fitness: Fitness): BsonValue?
suspend fun deleteById(objectId: ObjectId): Long
suspend fun findById(objectId: ObjectId): Fitness?
suspend fun updateOne(objectId: ObjectId, fitness: Fitness): Long
}

infrastructure 패키지 아래에 repository 패키지 만들고 repository 패키지 에 FitnessRepositoryImpl.kt 라는 파일 만듭니다. 이 파일 인터페이스의 메서드를 구현합니다. 다음 코드를 FitnessRepositoryImpl.kt 파일 에 복사합니다.

package com.mongodb.infrastructure.repository
import com.mongodb.MongoException
import com.mongodb.client.model.Filters
import com.mongodb.client.model.UpdateOptions
import com.mongodb.client.model.Updates
import com.mongodb.domain.entity.Fitness
import com.mongodb.domain.ports.FitnessRepository
import com.mongodb.kotlin.client.coroutine.MongoDatabase
import kotlinx.coroutines.flow.firstOrNull
import org.bson.BsonValue
import org.bson.types.ObjectId
class FitnessRepositoryImpl(
private val mongoDatabase: MongoDatabase
) : FitnessRepository {
companion object {
const val FITNESS_COLLECTION = "fitness"
}
override suspend fun insertOne(fitness: Fitness): BsonValue? {
try {
val result = mongoDatabase.getCollection<Fitness>(FITNESS_COLLECTION).insertOne(
fitness
)
return result.insertedId
} catch (e: MongoException) {
System.err.println("Unable to insert due to an error: $e")
}
return null
}
override suspend fun deleteById(objectId: ObjectId): Long {
try {
val result = mongoDatabase.getCollection<Fitness>(FITNESS_COLLECTION).deleteOne(Filters.eq("_id", objectId))
return result.deletedCount
} catch (e: MongoException) {
System.err.println("Unable to delete due to an error: $e")
}
return 0
}
override suspend fun findById(objectId: ObjectId): Fitness? =
mongoDatabase.getCollection<Fitness>(FITNESS_COLLECTION).withDocumentClass<Fitness>()
.find(Filters.eq("_id", objectId))
.firstOrNull()
override suspend fun updateOne(objectId: ObjectId, fitness: Fitness): Long {
try {
val query = Filters.eq("_id", objectId)
val updates = Updates.combine(
Updates.set(Fitness::exerciseType.name, fitness.exerciseType),
Updates.set(Fitness::notes.name, fitness.notes),
Updates.set(Fitness::details.name, fitness.details)
)
val options = UpdateOptions().upsert(true)
val result =
mongoDatabase.getCollection<Fitness>(FITNESS_COLLECTION)
.updateOne(query, updates, options)
return result.modifiedCount
} catch (e: MongoException) {
System.err.println("Unable to update due to an error: $e")
}
return 0
}
}
4

다음 코드를 Application.kt 파일에 붙여넣습니다. 이 코드는 다음 작업을 수행합니다.

  1. Gson 포맷터를 사용하여 JSON 직렬화 및 역직렬화를 처리하다 하도록 ContentNegotiation 플러그인을 설정합니다.

  2. Koin을 사용하여 종속성 주입 활성화

  3. /swagger 엔드포인트에서 사용할 수 있는 Swagger API 경로를 구성합니다.

package com.mongodb
import com.mongodb.application.routes.fitnessRoutes
import com.mongodb.domain.ports.FitnessRepository
import com.mongodb.infrastructure.repository.FitnessRepositoryImpl
import com.mongodb.kotlin.client.coroutine.MongoClient
import io.ktor.serialization.gson.gson
import io.ktor.server.application.Application
import io.ktor.server.application.install
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.plugins.swagger.swaggerUI
import io.ktor.server.routing.routing
import io.ktor.server.tomcat.EngineMain
import org.koin.dsl.module
import org.koin.ktor.plugin.Koin
import org.koin.logger.slf4jLogger
fun main(args: Array<String>): Unit = EngineMain.main(args)
fun Application.module() {
install(ContentNegotiation) {
gson {
}
}
install(Koin) {
slf4jLogger()
modules(module {
single { MongoClient.create(
environment.config.propertyOrNull("ktor.mongo.uri")?.getString() ?: throw RuntimeException("Failed to access MongoDB URI.")
) }
single { get<MongoClient>().getDatabase(environment.config.property("ktor.mongo.database").getString()) }
}, module {
single<FitnessRepository> { FitnessRepositoryImpl(get()) }
})
}
routing {
swaggerUI(path = "swagger-ui", swaggerFile = "openapi/documentation.yaml") {
version = "4.15.5"
}
fitnessRoutes()
}
}

application.conf 파일 열고 다음을 붙여넣습니다.

ktor {
deployment {
port = 8080
}
application {
modules = [ com.mongodb.ApplicationKt.module ]
}
mongo {
uri = ${?MONGO_URI}
database = ${?MONGO_DATABASE}
}
}

documentation.yaml 파일 열고 다음을 붙여넣습니다.

openapi: 3.0.0
info:
title: Fitness API
version: 1.0.0
description: |
This Swagger documentation file outlines the API specifications for a Fitness Tracker application built with Ktor and MongoDB. The API allows users to manage fitness records including creating new records, updating and deleting records by ID. The API uses the Fitness and FitnessDetails data classes to structure the fitness-related information.
paths:
/fitness:
post:
summary: Create a new fitness record
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/FitnessRequest'
responses:
'201':
description: Fitness created successfully
'400':
description: Bad request
/fitness/{id}:
get:
summary: Retrieve fitness record by ID
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Successful response
content:
application/json:
example: {}
'404':
description: Fitness not found
delete:
summary: Delete fitness record by ID
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Fitness deleted successfully
'400':
description: Bad request
'404':
description: Fitness not found
patch:
summary: Update fitness record by ID
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/FitnessRequest'
responses:
'200':
description: Fitness updated successfully
'400':
description: Bad request
'404':
description: Fitness not found
components:
schemas:
Fitness:
type: object
properties:
id:
type: string
format: uuid
exerciseType:
type: string
notes:
type: string
details:
$ref: '#/components/schemas/FitnessDetails'
required:
- id
- notes
- details
FitnessDetails:
type: object
properties:
durationMinutes:
type: integer
format: int32
distance:
type: number
format: double
caloriesBurned:
type: integer
format: int32
required:
- durationMinutes
- distance
- caloriesBurned
FitnessRequest:
type: object
properties:
exerciseType:
type: string
notes:
type: string
details:
$ref: '#/components/schemas/FitnessDetails'
required:
- exerciseType
- notes
- details

이 파일 API 가 /swagger-ui 엔드포인트를 통해 제공하는 메서드를 정의합니다.

5

이 단계에서는 다음 API 엔드포인트를 구현합니다.

  • GET /fitness/{id}: ID 로 운동 항목을 조회합니다.

  • POST /Fitness: 새 운동 항목을 생성합니다.

  • PATCH /fitness/{id}: 지정된 운동 항목을 업데이트합니다.

  • DELETE /fitness/{id}: 지정된 운동 항목을 삭제합니다.

application 패키지 아래에 routes 패키지 만들고 routes 패키지 에 FitnessRoutes.kt 라는 파일 만듭니다. 다음 코드를 FitnessRoutes.kt 파일 에 복사합니다.

package com.mongodb.application.routes
import com.mongodb.application.request.FitnessRequest
import com.mongodb.application.request.toDomain
import com.mongodb.domain.ports.FitnessRepository
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.call
import io.ktor.server.request.receive
import io.ktor.server.response.respond
import io.ktor.server.response.respondText
import io.ktor.server.routing.route
import io.ktor.server.routing.Route
import io.ktor.server.routing.post
import io.ktor.server.routing.delete
import io.ktor.server.routing.get
import io.ktor.server.routing.patch
import org.bson.types.ObjectId
import org.koin.ktor.ext.inject
fun Route.fitnessRoutes() {
val repository by inject<FitnessRepository>()
route("/fitness") {
post {
val fitness = call.receive<FitnessRequest>()
val insertedId = repository.insertOne(fitness.toDomain())
call.respond(HttpStatusCode.Created, "Created fitness with id $insertedId")
}
delete("/{id?}") {
val id = call.parameters["id"] ?: return@delete call.respondText(
text = "Missing fitness id",
status = HttpStatusCode.BadRequest
)
val delete: Long = repository.deleteById(ObjectId(id))
if (delete == 1L) {
return@delete call.respondText("Fitness Deleted successfully", status = HttpStatusCode.OK)
}
return@delete call.respondText("Fitness not found", status = HttpStatusCode.NotFound)
}
get("/{id?}") {
val id = call.parameters["id"]
if (id.isNullOrEmpty()) {
return@get call.respondText(
text = "Missing id",
status = HttpStatusCode.BadRequest
)
}
repository.findById(ObjectId(id))?.let {
call.respond(it.toResponse())
} ?: call.respondText("No records found for id $id")
}
patch("/{id?}") {
val id = call.parameters["id"] ?: return@patch call.respondText(
text = "Missing fitness id",
status = HttpStatusCode.BadRequest
)
val updated = repository.updateOne(ObjectId(id), call.receive())
call.respondText(
text = if (updated == 1L) "Fitness updated successfully" else "Fitness not found",
status = if (updated == 1L) HttpStatusCode.OK else HttpStatusCode.NotFound
)
}
}
}

앞의 코드는 API 엔드포인트와 해당 핸들러를 정의합니다.

애플리케이션 실행 plugins HTTP.ktRouting.kt전에, 및 파일 이 포함된 폴더를 삭제 Serialization.kt Application.kt.

6

MongoDB Atlas cluster 에서 연결 URI를 검색합니다. 이 작업을 수행하는 방법에 대한 자세한 내용은 MongoDB 에 연결 가이드 의 연결URI 섹션을 참조하세요.

application.conf 파일 열고 다음 구성 값을 추가합니다.

-DMONGO_URI= <your connection URI>
-DMONGO_DATABASE= <your database name>

IntelliJ에서 Application.kt 파일 로 이동하여 Run 버튼을 클릭합니다. 이제 웹 브라우저에서 http://localhost:8080/swagger-ui/ 로 이동하여 API 액세스 수 있습니다.

Ktor에 대해 자세히 학습 Ktor 문서를 참조하세요.

이 튜토리얼의 소스 코드 보려면 GitHub의 코틀린 (Kotlin) Ktor MongoDB Vector Search 리포지토리 참조하세요.

돌아가기

드라이버 서명 유효성 검사

이 페이지의 내용