This is a short overview of how to use server-side interface in KVision with the actual example. It contains just the basic concepts and ideas. You can find more information in the following chapters.
Let's assume we want to create an encoder application, that gets some text from the user and encodes it on the server with a chosen algorithm.
We start by defining our data model and service interface in the common (shared) source set. We have to declare our "business" encode
method as suspending. We annotate the service interface with @KVService
, which will allow KVision do all its "magic".
{% code title="Common.kt" %}
import io.kvision.annotations.KVService
enum class EncodingType {
BASE64, URLENCODE, HEX
}
@KVService
interface IEncodingService {
suspend fun encode(input: String, encodingType: EncodingType): String
}
{% endcode %}
KVision compiler plugin will automatically generate EncodingService
class, which implements IEncodingService
interface. To use this class in the frontend application it is recommended to use getService()
function (you can also just use the name of the generated class, but in such case your project will not compile in IDE until compiler plugin task is executed).
{% code title="FrontendApp.kt" %}
import io.kvision.remote.getService
val service = getService<IEncodingService>()
vPanel {
val input = textAreaInput()
val select = selectInput(listOf(EncodingType.BASE64.name to "Base64",
EncodingType.URLENCODE.name to "URL Encode", EncodingType.HEX.name to "Hex"))
val button = button("Encode")
val output = div()
button.onClick {
GlobalScope.launch {
val encodingType = select.value?.let { EncodingType.valueOf(it) } ?: EncodingType.BASE64
val result = service.encode(input.value ?: "", encodingType)
output.content = result
}
}
}
{% endcode %}
Notice we just call the encode
method and get the result value directly. All asynchronous operations are hidden by the framework. We only have to use a coroutine builder function (launch
in this case).
(For convenience we will use Ktor module in this chapter)
To create an actual implementation of our EncodingService
we just have to implement the methods of the service interface.
{% code title="Backend.kt" %}
import java.net.URLEncoder
import acme.Base64Encoder
import acme.HexEncoder
@Suppress("ACTUAL_WITHOUT_EXPECT")
actual class EncodingService : IEncodingService {
override suspend fun encode(input: String, encodingType: EncodingType): String {
return when (encodingType) {
EncodingType.BASE64 -> {
Base64Encoder.encode(input)
}
EncodingType.URLENCODE -> {
URLEncoder.encode(input, "UTF-8")
}
EncodingType.HEX -> {
HexEncoder.encode(input)
}
}
}
}
{% endcode %}
{% hint style="info" %}
The @Suppress("ACTUAL_WITHOUT_EXPECT")
annotation allows this class to compile in IDE before the code is generated by the plugin.
{% endhint %}
Finally, we initialize routing in the main application function.
{% code title="Main.kt" %}
import io.ktor.application.Application
import io.ktor.server.routing.*
import io.kvision.remote.applyRoutes
import io.kvision.remote.getServiceManager
import io.kvision.remote.kvisionInit
fun Application.main() {
routing {
applyRoutes(getServiceManager<IEncodingService>())
}
kvisionInit()
}
{% endcode %}
When we run our application everything will work automatically - a call on the client side will run the code on the server and the result will be sent back to the caller.
That's all - our first, fullstack KVision application is ready!
You can find "encoder-fullstack-ktor", a complete application based on this overview (with some visual enhancements of the GUI), in the kvision-examples repository on GitHub.