Skip to content

Declare Ktor failures with Spine and Arrow

Spine provides helper functions for the Arrow Typed Errors library. They are based on the Raise DSL and context parameters, a new feature in Kotlin 2.4.0.

See a demo

Interested in a complete demo? The Ktor + Arrow example uses Spine to define its API!

Declaring failures

Declaring failures with the Arrow compatibility modules is identical to declaring failures with the base Spine module. Read the dedicated article.

Server-side

Add a dependency on the server-arrow module:

build.gradle.kts
plugins {
    kotlin("jvm") version "…"
}

dependencies {
    implementation("dev.opensavvy.spine:server-arrow:VERSION") //(1)!
}
  1. List of versions
build.gradle.kts
plugins {
    kotlin("multiplatform") version "…"
}

kotlin {
    jvm()
    linuxX64()
    // add any other platform you want to target…

    sourceSets.commonMain.dependencies {
        api("dev.opensavvy.spine:server-arrow:VERSION") //(1)!
    }
}
  1. List of versions

When declaring routes, replace route by routeWithRaise:

the Arrow module adds:

routeWithRaise(Users.User.edit) {
    // …
}

The DSL is identical to usual Spine, but adds support for Raise for failure management.

For example, you can replace:

route(Users.User.edit) {
    if (body.user.name.length < 5)
        fail(UsernameTooShort)

    // …
}

by:

routeWithRaise(Users.User.edit) {
    ensure(body.user.name.length >= 5) { UsernameTooShort }
}
Raise in Ktor endpoints without Spine

If you want to use the Raise DSL with Ktor, but don't want to use Spine, you can use the module arrow-kt.io:arrow-raise-ktor-server.

Client-side

Add a dependency on the client-arrow module:

build.gradle.kts
plugins {
    kotlin("jvm") version "…"
}

dependencies {
    implementation("dev.opensavvy.spine:client-arrow:VERSION") //(1)!
}
  1. List of versions
build.gradle.kts
plugins {
    kotlin("multiplatform") version "…"
}

kotlin {
    jvm()
    linuxX64()
    // add any other platform you want to target…

    sourceSets.commonMain.dependencies {
        api("dev.opensavvy.spine:client-arrow:VERSION") //(1)!
    }
}
  1. List of versions

In addition to .bodyOrThrow(), .bodyOrNull() and .handle() (learn more), this module adds the .body() function which raises each failure.

context(Raise<NotFound>)
fun HttpClient.getUser(id: String): User =
    this.request(Users / User(id) / User.get).body()

fun HttpClient.getUserOrNull(id: String): User? =
    recover(block = { getUser(id) }, recover = { null })