rsocket-kotlin-router
is a customisable library designed to streamline and simplify routing
for RSocket Kotlin server applications. This library offers a typesafe DSL for handling various
routes, serving as a declarative simplified alternative to manual routing that would
otherwise result in long-winded ternary logic or exhaustive when statements.
Library provides the following features:
First of all, you need to implement basic artifacts with routing support. For now, rsocket-kotlin-router
is available only at my self-hosted maven:
repositories {
maven("https://maven.y9vad9.com")
}
dependencies {
implementation("com.y9vad9.rsocket.router:router-core:$version")
}
For now, it's available for JVM only, but as there is no JVM platform API used, new targets will be available upon your request.
Example of defining RSocket router:
val serverRouter = router {
routeSeparator = '.'
routeProvider { metadata: ByteReadPacket? ->
metadata?.read(RoutingMetadata)?.tags?.first()
?: throw RSocketError.Invalid("No routing metadata was provided")
}
routing { // this: RoutingBuilder
route("authorization") {
requestResponse("register") { payload: Payload ->
// just 4 example
println(payload.data.readText())
Payload.Empty
}
}
}
}
See also what else is supported:
Interceptors
Interceptors are experimental feature: API can be changed in the future.Preprocessors
Preprocessors are utilities that run before routing feature applies. For cases, when you need to transform input into
something or propagate
values using coroutines – you can
extend Preprocessor.Modifier
or Preprocessor.CoroutineContext
.
Here's an example:
class MyCoroutineContextElement(val value: String) : CoroutineContext.Element {... }
@OptIn(ExperimentalInterceptorsApi::class)
class MyCoroutineContextPreprocessor : Preprocessor.CoroutineContext {
override fun intercept(coroutineContext: CoroutineContext, input: Payload): CoroutineContext {
return coroutineContext + MyCoroutineContextElement(value = "smth")
}
}
Route Interceptors
In addition to the Preprocessors
, rsocket-kotlin-router
also provides API to intercept specific routes:
@OptIn(ExperimentalInterceptorsApi::class)
class MyRouteInterceptor : RouteInterceptor.Modifier {
override fun intercept(route: String, input: Payload): Payload {
return Payload.Empty // just for example
}
}
Installation
val serverRouter = router {
preprocessors {
forCoroutineContext(MyCoroutineContextPreprocessor())
}
sharedInterceptors {
forModification(MyRouteInterceptor())
}
}
Versioning support
Here's example of how request versioning looks like:
requestResponseV("foo") {
version(1) { payload: Payload ->
// handle requests for version "1.0"
Payload.Empty
}
version(2) { payload: Payload ->
// handle requests for version "2.0"
Payload.Empty
}
}
For details, please refer to the versioning guide.
Serialization support
Here is example of how type-safe requests with serialization/deserialization mechanisms look like:
requestResponse<Foo, Bar>("register") { foo: Foo ->
return@requestResponse Bar(/* ... */)
}
// or versioned variant:
requestResponseV("register") {
version(1) { foo: Foo ->
Bar(/* ... */)
}
version(2) { qux: Qux ->
FizzBuzz(/* ... */)
}
}
For details, please refer to the serialization guide.
Testing
rsocket-kotlin-router
provides ability to test your routes with router-test
artifact:
dependencies {
implementation("com.y9vad9.rsocket.router:router-test:$version")
}
@Test
fun testRoutes() {
runBlocking {
val route1 = router.routeAtOrAssert("test")
val route2 = router.routeAtOrAssert("test.subroute")
route1.assertHasInterceptor<MyInterceptor>()
route2.assertHasInterceptor<MyInterceptor>()
route2.fireAndForgetOrAssert(buildPayload {
data("test")
})
}
}
You can refer to the example for more details.
For bugs, questions and discussions please use the GitHub Issues.
This library is licensed under MIT License. Feel free to use, modify, and distribute it for any purpose.