Введение: Почему Kotlin и REST API?
Современная веб-разработка немыслима без REST API. Если вы уже знакомы с Python и фреймворками вроде Flask или FastAPI, то наверняка цените простоту и скорость создания серверных приложений. Kotlin, как современный язык для JVM, предлагает не меньшую элегантность и лаконичность, особенно в связке с фреймворком Ktor.
В этой статье мы за 30 минут создадим полноценное REST API на Kotlin. Вы научитесь настраивать проект, создавать маршруты, обрабатывать JSON и запускать сервер. Никакой воды — только практика.
Если вы хотите расширить свой стек технологий или просто попробовать Kotlin для backend-разработки, этот гайд для вас.
Шаг 1: Настройка проекта и зависимости
Для начала нам понадобится проект на Kotlin. Мы будем использовать сборщик Gradle (или Maven — на ваш выбор). Самый быстрый способ — создать проект через Ktor Project Generator.
Выберите следующие опции:
- Build System: Gradle Kotlin DSL
- Engine: Netty (или любой другой)
- Plugins: Content Negotiation (JSON), Routing, Status Pages
После скачивания архива распакуйте его и откройте в IntelliJ IDEA или другом редакторе.
Если вы создаёте проект вручную, добавьте в build.gradle.kts следующие зависимости:
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.kt — точку входа в приложение.
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.application.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json
fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
configureSerialization()
configureRouting()
}.start(wait = true)
}
fun Application.configureSerialization() {
install(ContentNegotiation) {
json(Json {
prettyPrint = true
isLenient = true
})
}
}
Готово! У нас есть базовая настройка для работы с JSON и сервер на порту 8080.
Шаг 2: Создание модели данных и хранилища
Для REST API нам нужны данные. Создадим простую модель User (пользователь) и временное in-memory хранилище.
Сначала определим data-класс с аннотацией @Serializable:
import kotlinx.serialization.Serializable
@Serializable
data class User(
val id: Int,
val name: String,
val email: String
)
Теперь создадим объект-репозиторий, который будет хранить пользователей:
object UserRepository {
private val users = mutableListOf(
User(1, "Иван Иванов", "ivan@example.com"),
User(2, "Мария Петрова", "maria@example.com")
)
fun getAll(): List<User> = users.toList()
fun getById(id: Int): User? = users.find { it.id == id }
fun add(user: User): User {
users.add(user)
return user
}
fun delete(id: Int): Boolean = users.removeIf { it.id == id }
}
Это простейшее решение, но для демонстрации за 30 минут оно идеально подходит.
Шаг 3: Настройка маршрутов (REST endpoints)
Теперь самое интересное — создадим эндпоинты для CRUD-операций. Добавим файл Routing.kt:
import io.ktor.server.routing.*
import io.ktor.server.response.*
import io.ktor.server.request.*
fun Application.configureRouting() {
routing {
route("/api/users") {
// GET /api/users — получить всех пользователей
get {
call.respond(UserRepository.getAll())
}
// GET /api/users/{id} — получить пользователя по ID
get("{id}") {
val id = call.parameters["id"]?.toIntOrNull()
if (id == null) {
call.respondText("Invalid ID", status = io.ktor.http.HttpStatusCode.BadRequest)
return@get
}
val user = UserRepository.getById(id)
if (user != null) {
call.respond(user)
} else {
call.respondText("User not found", status = io.ktor.http.HttpStatusCode.NotFound)
}
}
// POST /api/users — создать нового пользователя
post {
val user = call.receive<User>()
UserRepository.add(user)
call.respond(io.ktor.http.HttpStatusCode.Created, user)
}
// DELETE /api/users/{id} — удалить пользователя
delete("{id}") {
val id = call.parameters["id"]?.toIntOrNull()
if (id == null) {
call.respondText("Invalid ID", status = io.ktor.http.HttpStatusCode.BadRequest)
return@delete
}
val deleted = UserRepository.delete(id)
if (deleted) {
call.respondText("User deleted", status = io.ktor.http.HttpStatusCode.OK)
} else {
call.respondText("User not found", status = io.ktor.http.HttpStatusCode.NotFound)
}
}
}
}
}
Обратите внимание: мы используем call.receive<User>() для автоматической десериализации JSON в объект Kotlin. Это возможно благодаря установленному плагину Content Negotiation.
Шаг 4: Запуск и тестирование API
Всё готово! Запустите main() в вашем IDE. Сервер стартует на http://localhost:8080.
Протестируем API с помощью curl или Postman:
- GET /api/users — вернёт список всех пользователей.
- GET /api/users/1 — вернёт пользователя с ID=1.
- POST /api/users с телом
{"id":3,"name":"Сергей","email":"sergey@example.com"}— создаст нового пользователя. - DELETE /api/users/1 — удалит пользователя с ID=1.
Пример запроса через curl:
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application