Ознакомительный пример
Данный пример разбирает как создать простой сервис на Kora, с HTTP сервером, настроенными метриками, логгированием и пробами, который умеет отвечать на запрос GET /hello/world
.
Создание проекта¶
Создаем новый Gradle-проект (через IDEA или gradle init
).
Для работы нам потребуется gradlew
с настроенной версией Gradle выше 7.*
.
Проверим конфигурацию в gradle/wrapper/gradle-wrapper.properties
:
Настройка Gradle¶
Основные концепции и описание фреймворка можно прочесть на основной странице.
build.gradle
:
plugins {
id "java"
id "application"
}
repositories {
mavenCentral()
}
group = "ru.tinkoff.kora.example"
version = "0.1.0-SNAPSHOT"
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
mainClassName = "ru.tinkoff.kora.example.Application"
configurations {
koraBom
annotationProcessor.extendsFrom(koraBom)
compileOnly.extendsFrom(koraBom)
implementation.extendsFrom(koraBom)
api.extendsFrom(koraBom)
}
dependencies {
koraBom platform("ru.tinkoff.kora:kora-parent:1.1.15")
annotationProcessor "ru.tinkoff.kora:annotation-processors"
implementation "ru.tinkoff.kora:http-server-undertow"
implementation "ru.tinkoff.kora:json-module"
implementation "ru.tinkoff.kora:config-hocon"
implementation "ch.qos.logback:logback-classic:1.4.8"
}
build.gradle.kts
:
plugins {
kotlin("jvm") version ("1.9.10")
id("com.google.devtools.ksp") version ("1.9.10-1.0.13")
id("application")
}
repositories {
mavenCentral()
}
application {
mainClass.set("ru.tinkoff.kora.example.ApplicationKt")
}
val koraBom: Configuration by configurations.creating
configurations {
ksp.get().extendsFrom(koraBom)
compileOnly.get().extendsFrom(koraBom)
api.get().extendsFrom(koraBom)
implementation.get().extendsFrom(koraBom)
}
dependencies {
koraBom(platform("ru.tinkoff.kora:kora-parent:1.1.15"))
ksp("ru.tinkoff.kora:symbol-processors")
implementation("ru.tinkoff.kora:http-server-undertow")
implementation("ru.tinkoff.kora:json-module")
implementation("ru.tinkoff.kora:config-hocon")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.3")
implementation("ch.qos.logback:logback-classic:1.4.8")
}
kotlin {
jvmToolchain { languageVersion.set(JavaLanguageVersion.of("17")) }
sourceSets.main { kotlin.srcDir("build/generated/ksp/main/kotlin") }
sourceSets.test { kotlin.srcDir("build/generated/ksp/test/kotlin") }
}
tasks.distTar {
archiveFileName.set("application.tar")
}
Конфигурация приложения¶
Для запуска приложения нам нужно сформировать точку входа в приложение и контейнер зависимостей.
Для этого создадим интерфейс Application
с таким кодом:
Если мы запустим компиляцию, то будет создан класс ApplicationGraph
, в котором описано как собирать все компоненты нашего будущего контейнера зависимостей.
Что нам предоставляет модуль UndertowHttpServerModule
:
- Сервер для публичного апи на порту 8080
- Сервер для системного апи на порту 8085
- Пробы на системном порту: /system/liveness и /system/readiness
Далее нам нужно создать точку входа, добавим в класс Application
метод main
:
KoraApplication.run
запускает параллельную инициализацию всех компонентов в контейнере зависимостей
и блокирует основной поток до получения сигнала SIGTERM
, после этого приложение начинает штатное завершение.
Теперь, если мы запустим это приложение, то нам будут доступны маршруты по ссылкам выше.
Контроллер¶
Теперь давайте напишем контроллер, который будет обрабатывать запрос GET /hello/world
на публичном порту.
import ru.tinkoff.kora.common.Component;
import ru.tinkoff.kora.http.common.HttpHeaders;
import ru.tinkoff.kora.http.common.HttpMethod;
import ru.tinkoff.kora.http.common.annotation.HttpRoute;
import ru.tinkoff.kora.http.common.body.HttpBody;
import ru.tinkoff.kora.http.server.common.HttpServerResponse;
import ru.tinkoff.kora.http.server.common.annotation.HttpController;
import java.nio.charset.StandardCharsets;
@Component
@HttpController
public final class HelloWorldController {
@HttpRoute(method = HttpMethod.GET, path = "/hello/world")
public HttpServerResponse helloWorld() {
return HttpServerResponse.of(200, HttpBody.plaintext("Hello World"));
}
}
import ru.tinkoff.kora.common.Component
import ru.tinkoff.kora.http.common.HttpHeaders
import ru.tinkoff.kora.http.common.HttpMethod
import ru.tinkoff.kora.http.common.annotation.HttpRoute
import ru.tinkoff.kora.http.common.body.HttpBody
import ru.tinkoff.kora.http.server.common.HttpServerResponse
import ru.tinkoff.kora.http.server.common.annotation.HttpController
import java.nio.charset.StandardCharsets
@Component
@HttpController
class HelloWorldController {
@HttpRoute(method = HttpMethod.GET, path = "/hello/world")
fun helloWorld(): HttpServerResponse {
return HttpServerResponse.of(200, HttpBody.plaintext("Hello World"))
}
}
Давайте разберёмся детально:
@HttpController
- говорит, что этот класс контроллер@Component
- говорит, что мы хотим добавить этот класс в наш контейнер@HttpRoute
- описывает какой путь мы хотим обрабатыватьHttpServerResponse
- это сырой вариант ответа, в котором можно выставить что угодно и отдать любые байты
Для запуска приложения можно использовать команду:
Контроллер Json¶
В обычной жизни мы зачастую отдаём данные в формате Json
, для этого добавим модуль JsonModule
:
import ru.tinkoff.kora.common.KoraApp;
import ru.tinkoff.kora.config.hocon.HoconConfigModule;
import ru.tinkoff.kora.http.server.undertow.UndertowHttpServerModule;
import ru.tinkoff.kora.json.module.JsonModule;
@KoraApp
public interface Application extends HoconConfigModule, UndertowHttpServerModule, JsonModule { }
И изменим контроллер, чтобы он возвращал объект класса, который мы хотим сериализовать:
import ru.tinkoff.kora.common.Component;
import ru.tinkoff.kora.http.common.HttpMethod;
import ru.tinkoff.kora.http.common.annotation.HttpRoute;
import ru.tinkoff.kora.http.server.common.annotation.HttpController;
import ru.tinkoff.kora.json.common.annotation.Json;
@Component
@HttpController
public final class HelloWorldController {
record HelloWorldResponse(String greeting) {}
@Json
@HttpRoute(method = HttpMethod.GET, path = "/hello/world")
public HelloWorldResponse helloWorld() {
return new HelloWorldResponse("hello World");
}
}
import ru.tinkoff.kora.common.Component
import ru.tinkoff.kora.http.common.HttpMethod
import ru.tinkoff.kora.http.common.annotation.HttpRoute
import ru.tinkoff.kora.http.server.common.annotation.HttpController
import ru.tinkoff.kora.json.common.annotation.Json
@Component
@HttpController
class HelloWorldController {
data class HelloWorldResponse(val greeting: String)
@Json
@HttpRoute(method = HttpMethod.GET, path = "/hello/world")
fun helloWorld(): HelloWorldResponse {
return HelloWorldResponse("Hello World")
}
}
Теперь для нашего объекта будет сформирован оптимальный Json писатель и в ответе мы увидим Json:
Создать новый Java сервис можно использовав шаблон на GitHub
Создать новый Kotlin сервис можно использовав шаблон на GitHub