Functions in a remote interface are just regular functions in Kotlin that, when connected to a Web Frame, can be invoked from the web layer.

Examples

Functions can be declared any number of ways. The following examples are for a remote function that responds with the data that is sent to it from the web layer.

Declared as a function

fun echo(call: Call) {
    call.respond(call.request.data)
}

Declared as a method within a class

class Echo {
    fun echo(call: Call) {
        call.respond(call.request.data)
    }
}

Declared as a lambda

functions = mapOf(
    "echo" to { call ->
        call.respond(call.request.data)
    },
),

Web Frame Configuration

For the following example, we’ll be using a function declared like the following:

fun echo(call: Call) {
    call.respond(call.request.data)
}

Since functions have first-class support in Kotlin, we can pass them as references to the Web Frame configuration.

val configuration = WebFrame.Configuration(
    baseUrl: ...
    functions = mapOf(
        "echo" to ::echo,
    ),
    observables = emptyMap(),
)

Peregrine expects remote functions to match the following type in Kotlin.

typealias RemoteFunction = (Call) -> Unit

Android API

Call

An instance of the Call class represents a single invocation of a remote function.

Properties

val request: Request

The Request instance associated with this call.

Methods

fun respond()

Complete the call by responding with empty data.

fun respond(text: String)

Complete the call by responding with a UTF-8 encoded string.

fun respond(data: JsonElement)

Complete the call by responding with arbitrary data.

Data must be JSON content on Android. One delightful way of creating arbitrary JSON content is by using the buildJsonObject helper from the KotlinX Serialization library:

call.respond(buildJsonObject {
    put("width", 100)
    put("height", 100)
})
inline fun <reified T> respond(json: T)

Complete the call by responding with a serializable object.

The easiest way to make a class serializable is by annotating it with @Serializable from the KotlinX Serialization library:

import kotlinx.serialization.*
import kotlinx.serialization.json.*

@Serializable
data class SizeResponse(val width: Double, val height: Double)

Then, objects can be passed to .respond() directly:

call.respond(SizeResponse(100, 100))

This function uses Json.encodeToJsonElement under the hood to serialize almost any data type: strings, booleans, ints, doubles, as well as any instances of classes annotated with @Serializable. For more information, see the docs for KotlinX Serialization.

fun fail(message: String = "Error", code: String? = null)

Complete the call (marking it as failed) by responding with an error message and code.

This will cause the web client to throw a ClientError exception.

Request

Contains the request data from the web layer and helpers to extract it.

Properties

val data: JsonElement

The raw data from the web layer.

val text: String

The data decoded as a UTF-8 string.

Methods

inline fun <reified T> json(): T

The data converted to a serializable object.

Annotate classes with @Serializable:

@Serializable
data class SizeRequest(
    val name: String
)

Then, pass the type as a generic parameter to .json():

val sizeRequest = call.request.json<SizeRequest>()
val shapeName = sizeRequest.name

This function uses Json.decodeFromJsonElement under the hood to deserialize into almost any data type.