Какво е Ktor?

На пръв поглед Ktor (произнася се Kay-tor) изглежда като друга асинхронна рамка за уеб приложения и донякъде е така. Ако имате някакъв опит с рамки като Express.js или Gin, ще се почувствате като у дома си с декларативния характер на Ktor. Ktor е разработен изцяло в Kotlin от екипа, който стои зад самия език. Споменах ли също, че функционира страхотно като HTTP клиент? Но това е тема за бъдеща публикация, засега нека се придържаме към сървърната страна на нещата.

Изисквания

Можете да използвате любимата си IDE за работа. Обичам да използвам IntelliJ Community Edition, защото работи перфектно с Kotlin. Тук няма нужда от най-доброто издание, но ако притежавате лиценза, можете да използвате приставката Ktor за някои допълнителни функции.

Що се отнася до времето за изпълнение, бих препоръчал да използвате GraalVM 11, той зарежда всичко бързо и има много малко памет. Всичко с OpenJDK, така че и тук няма проблеми с лиценза.

Е, сега, след като всичко е настроено и готово за работа, нека да започнем.

Използване на Ktor стартер

Най-лесният начин да създадете проект с Ktor е като отидете на https://start.ktor.io/#. Това е генераторът на проекти за Ktor, където ще настроим повечето от нашите първоначални функции.

Първо, нека поговорим за наличните настройки в най-левия панел.

Ще използваме Gradle като инструмент за изграждане с Kotlin DSL, което го прави много чист и четлив, ако предпочитате да използвате Gradle такъв, какъвто е, или дори да използвате Maven, можете да го изберете с първото поле.

Както ще видите в тази поредица, Ktor е много гъвкав, така че ни позволява да изберем на какъв сървърен двигател искаме да стартираме нашия проект. Досега имах успех с Netty, работи страхотно на платформи като Heroku, които можете лесно да внедрите чрез техния CLI. Не се тревожете за това сега обаче, ще го разгледаме в бъдеща публикация.

След това трябва да определим кои функции бихме искали да инсталираме в нашия проект. Всички те могат да бъдат инсталирани и по-късно, но за днешната статия ще проверим всичко необходимо, за да започнем с подходящ API.

От сървърния панел с функции трябва да изберете:

  • Заглавки по подразбиране (от „Функции“)

  • Маршрутизиране (от „Функции“)

  • Договаряне на съдържанието (от „Договаряне на съдържанието“)

Това е всичко, това е всичко, което трябва да инсталираме, за да започнем да отговаряме на HTTP заявки. Сега щракнете върху „Изграждане“ в долния ляв ъгъл на екрана и извлечете съдържанието на папката, където желаете.

Отворете проекта си в IntelliJ и изчакайте Gradle да се разреши. Това може да отнеме известно време, особено ако за първи път изтегляте всички артефакти.

Нека започнем с обиколка на нашия проект. Първо, погледнете папката „ресурси“. Имаме файл, наречен „application.conf“, името казва всичко, но помислете за това като за конфигурационен файл на вашата среда, трябва да използвате този файл, за да съхранявате API ключове на трети страни, настройки на сървъра и общо взето всичко, което сметнете за необходимо. Вие също използвате този файл, за да кажете какви модули Ktor трябва да зареди при стартиране.

Имайте предвид, че добавих възел, наречен „myCustomNode“, това означава, че можем да декларираме всичко, от което се нуждаем, в този файл и ще можем да го извлечем по време на изпълнение.

Сега обърнете внимание на модула на възела, зареден на ред 11, след което се насочете към „src/Application.kt“, забележете, че зареденият модул препраща точно към този файл, плюс „.module” в края.

Защо „.module“? Може да попитате. Е, Ktor използва интензивно езикова функция, наречена „Функции за разширение“, можете да прочетете повече за това тук. Забележете, че вътре в “Application.kt”, създадохме функцията “.module” за класа “Application”, следователно, ето защо трябва да го посочим във файла „application.conf“.

Преди да продължим, нека проверим дали всичко работи добре. Отидете в менюто Gradle, разгънете менюто „Задачи“, след това „Приложение“ и щракнете двукратно върху „изпълни“.

Сървърът трябва да стартира и вашият терминал ще изглежда така.

Ако имате проблеми с изпълнението на приложението, не се притеснявайте, вероятно е просто някаква грешна конфигурация във вашия JDK, напишете коментар и ме уведомете как мога да помогна.

Както и да е, отидете на http://localhost:8080/ и ето го. Доброто старо „HELLO WORLD!“

Спрете сървъра и нека поговорим за състава на „Application.kt“. Първо, може да забележите няколко анотации над модула, който декларираме. Първият е чисто, така че IntelliJ да не ни притеснява да не използваме изрично функцията, която декларираме. Към момента на писане, IDE все още няма информация за връзката между „application.conf” и „Application.kt”, така че ще ни предупреди за това. Можете да го премахнете, ако предупрежденията за компилация не ви плашат.

Втората анотация казва, че по време на компилиране компилаторът трябва да генерира претоварвания на този метод, тъй като JVM не поддържа незадължителни параметри по подразбиране. Това е така, защото нашият параметър „тестване“ не е задължителен. На този етап няма да обхващаме тестването, така че нека се отървем от него и малко да почистим нашия файл. Оригиналният „Application.kt“ изглеждаше така.

След почистването трябва да изглежда така.

Премахнах анотацията и незадължителния параметър, забележете, че премахнах и името на пакета на файла, трябва да отразите тази промяна и във вашия файл „application.conf“. Разбира се, това е въпрос на предпочитание, така че го направете, ако ви харесва по този начин.

Ако сте премахнали името на пакета на вашия файл „Application.kt“, трябва да промените заредения модул от „com.example.ApplicationKt.module“ на просто „ApplicationKt.module“

Характеристика

Може би си спомняте, че инсталирахме няколко функции, докато генерирахме проекта, тук виждаме как тези функции оживяват. Всяка функция, която добавяте към вашия проект с мениджъра на зависимости по ваш избор, трябва да бъде инсталирана при стартиране. Това е, което правим, когато пишем „install()“ в нашия код.

Този метод получава обект от тип ApplicationFeature‹T› и интерфейса SAM („Какво е интерфейс SAM?“), след като ни даде възможност да конфигурираме функцията според нуждите.

Забележете, че след като инсталирахме функцията „DefaultHeaders“, можем да зададем и други заглавки, тъй като интерфейсът ни предоставя обект за конфигурация.

Това е философията на работа с всяка функция, която инсталирате на Ktor. Нека да разгледаме функцията ContentNegotiation и да се заемем с писането на код.

ContentNegotiation е функцията, която ни позволява да сериализираме съдържание за нашите клиенти, но, както споменах преди, Ktor е много гъвкав и ни дава възможност да използваме каквато машина за сериализация ни харесва.

Ще използваме официална библиотека, наречена „kotlinx.serialization“, за да сериализираме нашите данни като JSON. За целта се насочете към вашия файл “build.gradle”. И приложете промените, споменати по-долу.

След това заредете промените в Gradle.

Забележете, че „json()“ вече може да се импортира. Продължете и го импортирайте.

Това е всичко, ние сме готови да изпратим JSON отговори на нашите клиенти.

Не забравяйте да анотирате класовете, които искате да сериализирате като JSON с анотацията @Serializable.

Маршрутизиране

Може да сте забелязали, че нашата крайна точка Hello World е регистрирана точно тук в нашия файл “Application.kt”, това не е добре, когато вашият API има много крайни точки, така че ще ви покажа как да групирате маршрути в отделни файлове. Продължете и създайте пакет, наречен „dog“ и файл на Kotlin, наречен „DogRoute“, и друг файл на Kotlin, наречен „Dog“ (това трябва да бъде клас данни), така трябва да изглежда вашата структура.

Вашият файл “Dog.kt” трябва да изглежда така.

И вашият файл “DogRoutes.kt” трябва да изглежда така.

След това отидете на вашия “Application.kt” и декларирайте “dogRoutes()” вместо изрично да създавате маршрутите, както беше преди.

Сега нека създадем нашия „DogService.kt“, този клас ще отговаря за предоставянето на данните, които ще изобразяваме с нашия рутер. Помислете за “DogRoutes.kt” като за вашия контролер в MVC архитектурата. Разбира се, ще запазите „DogService.kt“ в пакета „dog“.

Нека да продължим и да приложим тези методи в „DogRoutes.kt“.

Сега нека стартираме нашето приложение и да тестваме всичко. Ще използвам Insomnia за това, но можете да използвате всичко, което плава в лодката ви.

Както можете да видите, всичко работи чудесно! Преди да завършим това, има няколко разхлабени възела в нашето приложение, които трябва да посоча:

  • Трябва да създаваме „DogService“ ръчно всеки път, когато имаме нужда от него. Това е темата на следващата ни статия: Инжектиране на зависимости с помощта на Koin;
  • Нека бъдем честни, това е безполезно без слой за постоянство, затова ще го разгледаме и в бъдеща публикация, като използваме Ktorm.

Надявам се, че сте успели да направите първите стъпки с Ktor днес, ако имате нужда от нещо, не се колебайте да се свържете с мен за допълнителна информация.

Трябва също така да посоча няколко страхотни учебни материала, ако искате да научите повече за Kotlin или Ktor.

Можете да намерите целия изходен код тук.

До следващия път!