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.

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 our module server-arrow-independent which adds the function raise to regular Ktor endpoints.

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 })