Как написать REST API на Kotlin за 30 минут

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

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

Начать курс

Введение

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

Шаг 1: Настройка проекта и зависимости

Для быстрого старта используем IntelliJ IDEA (Community Edition) или любой другой редактор. Создадим новый проект Gradle с Kotlin DSL.

Создание структуры проекта

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

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

repositories {
    mavenCentral()
}

dependencies {
    implementation("io.ktor:ktor-server-core:2.3.7")
    implementation("io.ktor:ktor-server-netty:2.3.7")
    implementation("io.ktor:ktor-server-content-negotiation:2.3.7")
    implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.7")
    implementation("org.jetbrains.exposed:exposed-core:0.44.1")
    implementation("org.jetbrains.exposed:exposed-dao:0.44.1")
    implementation("org.jetbrains.exposed:exposed-jdbc:0.44.1")
    implementation("com.h2database:h2:2.2.224")
    implementation("ch.qos.logback:logback-classic:1.4.14")
}

application {
    mainClass.set("ApplicationKt")
}

Мы используем:

  • Ktor — легковесный асинхронный фреймворк для HTTP-серверов.
  • Exposed — ORM для работы с базами данных.
  • H2 — встроенная база данных для разработки.
  • Kotlinx.serialization — для работы с JSON.

Шаг 2: Создание модели данных и подключение БД

Определим структуру таблицы задач. Создайте файл Database.kt:

import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction

object Tasks : Table() {
    val id = integer("id").autoIncrement()
    val title = varchar("title", 255)
    val completed = bool("completed").default(false)

    override val primaryKey = PrimaryKey(id)
}

data class Task(val id: Int, val title: String, val completed: Boolean)

fun initDatabase() {
    Database.connect("jdbc:h2:mem:test", driver = "org.h2.Driver")
    transaction {
        SchemaUtils.create(Tasks)
    }
}

Этот код создаёт таблицу Tasks с тремя полями: id, title и completed. Функция initDatabase() инициализирует базу данных в памяти.

Шаг 3: Написание контроллеров REST API

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

Базовая настройка сервера

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) {
        install(ContentNegotiation) {
            json()
        }
        initDatabase()
        configureRouting()
    }.start(wait = true)
}

Реализация эндпоинтов CRUD

fun Application.configureRouting() {
    routing {
        // Получить все задачи
        get("/tasks") {
            val tasks = transaction {
                Tasks.selectAll().map { row ->
                    Task(
                        id = row[Tasks.id],
                        title = row[Tasks.title],
                        completed = row[Tasks.completed]
                    )
                }
            }
            call.respond(tasks)
        }

        // Создать задачу
        post("/tasks") {
            val task = call.receive<Task>()
            val id = transaction {
                Tasks.insert {
                    it[title] = task.title
                    it[completed] = task.completed
                } get Tasks.id
            }
            call.respond(mapOf("id" to id, "status" to "created"))
        }

        // Обновить задачу
        put("/tasks/{id}") {
            val id = call.parameters["id"]?.toIntOrNull()
            if (id == null) {
                call.respondText("Invalid ID", status = io.ktor.http.HttpStatusCode.BadRequest)
                return@put
            }
            val updatedTask = call.receive<Task>()
            transaction {
                Tasks.update({ Tasks.id eq id }) {
                    it[title] = updatedTask.title
                    it[completed] = updatedTask.completed
                }
            }
            call.respond(mapOf("status" to "updated"))
        }

        // Удалить задачу
        delete("/tasks/{id}") {
            val id = call.parameters["id"]?.toIntOrNull()
            if (id == null) {
                call.respondText("Invalid ID", status = io.ktor.http.HttpStatusCode.BadRequest)
                return@delete
            }
            transaction {
                Tasks.deleteWhere { Tasks.id eq id }
            }
            call.respond(mapOf("status" to "deleted"))
        }
    }
}

Мы создали четыре эндпоинта:

  • GET /tasks — получение списка всех задач.
  • POST /tasks — создание новой задачи.
  • PUT /tasks/{id} — обновление существующей задачи.
  • DELETE /tasks/{id} — удаление задачи.

Шаг 4: Запуск и тестирование API

Запустите приложение. Сервер стартует на порту 8080. Для тестирования используйте Postman, curl или браузер.

Примеры запросов

  • GET http://localhost:8080/tasks — вернёт пустой массив [].
  • POST http://localhost:8080/tasks с телом {"title": "Изучить Kotlin", "completed": false} — создаст задачу.
  • PUT

Блоги

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