
Lightweight, feature-rich declarative error handling framework for functional programming, offering 90+ operators. Ensures compile-time error handling and enhances code readability and extensibility through Railway Programming principles.
ApiResult is a Kotlin Multiplatform declarative error handling framework that is performant, easy to use and feature-rich.
ApiResult is Railway Programming and functional error handling on steroids.
Exceptions in Kotlin are unchecked. Each time you call a function, it can throw and crash you app. With ApiResult, you will never have this problem again.
// wrap a result of any computation and expose the result
class BillingRepository(private val api: RestApi) {
suspend fun getSubscriptions() = ApiResult {
api.getSubscriptions()
} // -> ApiResult<List<Subscription>?>
}
// obtain and handle the result in the client code
fun onClickVerify() {
val state: SubscriptionState = billingRepository.getSubscriptions()
.errorOnNull() // map nulls to error states with compile-time safety
.recover<NotSignedInException, _> { emptyList() } // recover from some or all errors
.require { securityRepository.isDeviceTrusted() } // conditionally fail the chain
.mapValues(::SubscriptionModel) // map list items
.filter { it.isPurchased } // filter
.mapError<NetworkException, _, _> { e -> BillingException(cause = e) } // map exceptions
.then { validateSubscriptions(it) } // execute a computation and continue with its result, propagating errors
.chain { updateGracePeriod(it) } // execute another computation, and if it fails, stop the chain
.onError { subscriptionService.disconnect() } // executed on error
.onEmpty { return SubscriptionState.NotSubscribed } // use non-local returns and short-circuit evaluation
.fold(
onSuccess = { SubscriptionState.Subscribed(it) },
onError = { SubscriptionState.Error(it) },
) // unwrap the result to another value
// ...
}[versions]
apiresult = "< Badge above ππ» >"
[dependencies]
apiresult = { module = "pro.respawn.apiresult:core", version.ref = "apiresult" } dependencies {
// usually you will want to expose ApiResult types in your module APIs, so consider using api() for the dependency
commonMainApi("pro.respawn.apiresult:core:<version>")
}Ready to try? Start with reading the Quickstart Guide.
Copyright 2022-2026 Respawn Team and contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
ApiResult is a Kotlin Multiplatform declarative error handling framework that is performant, easy to use and feature-rich.
ApiResult is Railway Programming and functional error handling on steroids.
Exceptions in Kotlin are unchecked. Each time you call a function, it can throw and crash you app. With ApiResult, you will never have this problem again.
// wrap a result of any computation and expose the result
class BillingRepository(private val api: RestApi) {
suspend fun getSubscriptions() = ApiResult {
api.getSubscriptions()
} // -> ApiResult<List<Subscription>?>
}
// obtain and handle the result in the client code
fun onClickVerify() {
val state: SubscriptionState = billingRepository.getSubscriptions()
.errorOnNull() // map nulls to error states with compile-time safety
.recover<NotSignedInException, _> { emptyList() } // recover from some or all errors
.require { securityRepository.isDeviceTrusted() } // conditionally fail the chain
.mapValues(::SubscriptionModel) // map list items
.filter { it.isPurchased } // filter
.mapError<NetworkException, _, _> { e -> BillingException(cause = e) } // map exceptions
.then { validateSubscriptions(it) } // execute a computation and continue with its result, propagating errors
.chain { updateGracePeriod(it) } // execute another computation, and if it fails, stop the chain
.onError { subscriptionService.disconnect() } // executed on error
.onEmpty { return SubscriptionState.NotSubscribed } // use non-local returns and short-circuit evaluation
.fold(
onSuccess = { SubscriptionState.Subscribed(it) },
onError = { SubscriptionState.Error(it) },
) // unwrap the result to another value
// ...
}[versions]
apiresult = "< Badge above ππ» >"
[dependencies]
apiresult = { module = "pro.respawn.apiresult:core", version.ref = "apiresult" } dependencies {
// usually you will want to expose ApiResult types in your module APIs, so consider using api() for the dependency
commonMainApi("pro.respawn.apiresult:core:<version>")
}Ready to try? Start with reading the Quickstart Guide.
Copyright 2022-2026 Respawn Team and contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.