Как написать REST API на Kotlin за 30 минут: пошаговое руководство

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение

Kotlin — это современный, лаконичный и безопасный язык программирования, который набирает популярность в разработке серверных приложений. Благодаря своей совместимости с Java и мощным фреймворкам, таким как Ktor, вы можете создать полноценный REST API буквально за полчаса. В этой статье мы покажем, как написать REST API на Kotlin с использованием фреймворка Ktor, даже если вы новичок.

Мы создадим простое приложение для управления списком задач (Todo API) с поддержкой CRUD операций: создание, чтение, обновление и удаление. Весь процесс займет не более 30 минут, если следовать инструкции.

1. Подготовка проекта и зависимости

Для начала вам понадобится IntelliJ IDEA (Community Edition) и Gradle. Создадим новый проект Kotlin с поддержкой Ktor.

Шаг 1: Создание Gradle-проекта

Откройте IntelliJ IDEA и создайте новый проект: File → New → Project. Выберите Gradle и укажите язык Kotlin. Нажмите Finish.

Шаг 2: Добавление зависимостей Ktor

Откройте файл build.gradle.kts и добавьте следующие зависимости:

plugins {
    kotlin("jvm") version "1.9.0"
    application
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("io.ktor:ktor-server-core:2.3.0")
    implementation("io.ktor:ktor-server-netty:2.3.0")
    implementation("io.ktor:ktor-server-content-negotiation:2.3.0")
    implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.0")
    implementation("ch.qos.logback:logback-classic:1.4.11")
}

application {
    mainClass.set("ApplicationKt")
}

Нажмите кнопку Sync Now в правом верхнем углу, чтобы загрузить зависимости.

2. Создание модели данных и сервиса

Прежде чем писать маршруты, определим модель данных для нашей задачи и простой сервис для хранения данных в памяти.

Модель TodoItem

Создайте файл TodoItem.kt в папке src/main/kotlin:

import kotlinx.serialization.Serializable

@Serializable
data class TodoItem(
    val id: Int,
    val title: String,
    val completed: Boolean = false
)

Сервис TodoService

Создайте файл TodoService.kt:

import java.util.concurrent.atomic.AtomicInteger

class TodoService {
    private val items = mutableListOf<TodoItem>()
    private val idCounter = AtomicInteger(1)

    fun getAll(): List<TodoItem> = items.toList()

    fun getById(id: Int): TodoItem? = items.find { it.id == id }

    fun create(title: String): TodoItem {
        val newItem = TodoItem(id = idCounter.getAndIncrement(), title = title)
        items.add(newItem)
        return newItem
    }

    fun update(id: Int, title: String?, completed: Boolean?): TodoItem? {
        val index = items.indexOfFirst { it.id == id }
        if (index == -1) return null
        val current = items[index]
        val updated = current.copy(
            title = title ?: current.title,
            completed = completed ?: current.completed
        )
        items[index] = updated
        return updated
    }

    fun delete(id: Int): Boolean = items.removeAll { it.id == id }
}

3. Настройка сервера и маршрутов

Теперь создадим основной файл приложения Application.kt и пропишем маршруты REST API.

import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.routing.*
import io.ktor.server.response.*
import io.ktor.server.request.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.plugins.contentnegotiation.*

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

fun Application.configureSerialization() {
    install(ContentNegotiation) {
        json()
    }
}

fun Application.configureRouting() {
    val service = TodoService()

    routing {
        // GET /todos — получить все задачи
        get("/todos") {
            call.respond(service.getAll())
        }

        // GET /todos/{id} — получить задачу по ID
        get("/todos/{id}") {
            val id = call.parameters["id"]?.toIntOrNull()
            if (id == null) {
                call.respondText("Invalid ID", status = io.ktor.http.HttpStatusCode.BadRequest)
                return@get
            }
            val item = service.getById(id)
            if (item != null) {
                call.respond(item)
            } else {
                call.respondText("Not Found", status = io.ktor.http.HttpStatusCode.NotFound)
            }
        }

        // POST /todos — создать новую задачу
        post("/todos") {
            val request = call.receive<TodoItem>()
            val newItem = service.create(request.title)
            call.respond(newItem, status = io.ktor.http.HttpStatusCode.Created)
        }

        // PUT /todos/{id} — обновить задачу
        put("/todos/{id}") {
            val id = call.parameters["id"]?.toIntOrNull()
            if (id == null) {
                call.respondText("Invalid ID", status = io.ktor.http.HttpStatusCode.BadRequest)
                return@put
            }
            val request = call.receive<TodoItem>()
            val updated = service.update(id, request.title, request.completed)
            if (updated != null) {
                call.respond(updated)
            } else {
                call.respondText("Not Found", status = io.ktor.http.HttpStatusCode.NotFound)
            }
        }

        // DELETE /todos/{id} — удалить задачу
        delete("/todos/{id}") {
            val id = call.parameters["id"]?.toIntOrNull()
            if (id == null) {
                call.respondText("Invalid ID", status = io.ktor.http.HttpStatusCode.BadRequest)
                return@delete
            }
            if (service.delete(id)) {
                call.respondText("Deleted", status = io.ktor.http.HttpStatusCode.OK)
            } else {
                call.respondText("Not Found", status = io.ktor.http.HttpStatusCode.NotFound)
            }
        }
    }
}

4. Запуск и тестирование API

Запустите приложение, нажав зеленую стрелку рядом с функцией main(). Сервер стартует на порту 8080.

Тестирование с помощью curl

Откройте терминал и выполните следующие команды:

  • Создать задачу: curl -X POST http://localhost:8080/todos -H "Content-Type: application/json" -d

Блоги

Рекомендаций по книгам