### ApiResult Operators Reference Source: https://github.com/respawn-app/apiresult/blob/master/docs/quickstart.md Comprehensive list of ApiResult operators for creating, transforming, and folding computation results, including examples for error handling and value extraction. ```APIDOC Operators: Create: ApiResult { computation() }: Description: Wrap the result of a computation. ApiResult.flow { computation() }: Description: Produce a flow. ApiResult(value): Description: Either Error or Success based on the type of the value. runResulting { computation() }: Description: For parity with `runCatching`. ApiResult(): Description: Start with an `ApiResult` and then run mapping operators such as `then`. Useful when you want to check some conditions or evaluate other properties before executing an expensive operation. Fold results: val (result, error) = ApiResult { ... }: Description: Disassemble the result into two nullable types: `T?` of success, and `Exception?` of error. or(value): Description: Returns `value` if the result is an Error. orElse { computeValue() }: Description: Returns the result of `computeValue()`. orNull(): Description: Return `null` if the result is an `Error`. exceptionOrNull(): Description: If the result is an error, returns the exception and discards the result. orThrow(): Description: Throw `Error`s. This is the same as the binding operator from functional programming. fold(onSuccess = { /* ... */ }, onError = { /* ... */ }): Description: Fold the result to another type. onSuccess { computation(it) }: Description: Execute an operation if the result is a `Success`. `it` is the result value. onError { e -> e.fallbackValue }: Description: Execute `onError` if exception is of type `CustomException`. onLoading { setLoading(true) }: Description: Execute an operation if the result is `Loading`. ! (bang) operator: Description: Get the result or throw if it is an `Error`. It is the same as Kotlin's `!!` or calling `orThrow()`. Example: val result: ApiResult = ApiResult(1) val value: Int = !result ``` -------------------------------- ### ApiResult Usage Examples in Kotlin Source: https://github.com/respawn-app/apiresult/blob/master/docs/quickstart.md Demonstrates how to wrap synchronous and asynchronous computations using ApiResult, including a flow-based approach and handling nested coroutines with SuspendResult. ```kotlin // wrap a result of a computation suspend fun getSubscriptions(userId: String): ApiResult> = ApiResult { api.getSubscriptions(userId) } // emits: Loading -> Success / Error fun getSubscriptionsAsync(userId: String): Flow>> = ApiResult.flow { api.getSubscriptions(id) } // SuspendResult will wait for the result of nested coroutines and propagate exceptions thrown in them suspend fun getVerifiedSubs(userId: String) = SuspendResult { // this: CoroutineScope val subs = api.getSubscriptions(userId) launch { api.verifySubscriptions(subs) } launch { storage.saveSubsscriptions(subs) } subs } ``` -------------------------------- ### Handling Multiple Results with ApiResult (Kotlin) Source: https://github.com/respawn-app/apiresult/blob/master/docs/quickstart.md Demonstrates how ApiResult simplifies the process of binding multiple operation results, similar to monad comprehensions. The '!' operator is used to extract successful results, halting computation and returning an error if any intermediate operation fails. This example shows chaining repository calls for user verification, user retrieval, and subscription fetching. ```kotlin interface Repository { fun getUser(): ApiResult fun getSubscriptions(user: User): ApiResult> fun verifyDevice(): ApiResult } val subscriptions: ApiResult> = ApiResult { // bang (!) operator throws Errors, equivalent to binding // if bang does not throw, the device is verified val verificationResult = !repo.verifyDevice() // if bang does not throw, user is logged in val user: User = !userRepository.getUser() !repo.getSubscriptions(user) } ``` -------------------------------- ### Publishing a game with sequential API calls and progress reporting in Android Worker Source: https://github.com/respawn-app/apiresult/blob/master/docs/examples.md This Kotlin code snippet demonstrates a `doWork()` method for an Android Worker, handling the complex process of publishing a game. It involves multiple sequential API calls, progress reporting, and robust error handling using the `ApiResult` library. The process halts if any operation fails, ensuring resource cleanup and preventing unhandled exceptions. ```kotlin // created a custom operator for logging to logcat inline fun ApiResult.log() = onSuccess { Logger.v { "ApiResult Success: $it" } } onError { e -> Logger.e { "ApiResult Error: $e" } } class PublishGameWorker : CoroutineWorker(context, workerParams) { // we started with an empty result to defer the computations until checks pass override suspend fun doWork() = ApiResult() .tryMap { inputData.getLong(DATA_LOCAL_GAME_ID, 0L) } // then tried to get worker parameters .requireNotNull() // and required the data to be not null. Failure on this step will cancel the worker already .map(GameId::Local) // mapped the long to game id class .tryMap { repo.getLocalGameSync(it) } // then tried to get the game .requireNotNull() // failing if the game was not found .tryChain { updateProgress(POSTING_GAME_DATA) } // then tried to update worker progress safely .then { game -> // proceeding to load the local game's data repo.loadGameData(game) // first finding the data .then { data -> repo.publishGame(game, data) } // and then publishing that data safely } .tryChain { updateProgress(WorkerProgressState.GETTING_VIDEO_URLS) } // updating the progress again .tryMap { game -> // here we wanted to preserve the previous result and add another one to it. We used the Pair class // and monad comprehensions with tryMap() and bang operator (!) to achieve the desired outcome val id = !game.getRemoteId() val url = !repo.getGameUrl(id) game to url } .tryChain { updateProgress(UPLOADING_VIDEO, 0f) } .chain { (game, url) -> uploadVideo(url, game.videoUri) } // then chained another API call .map { (game, _) -> game } // thrown away the now unnecessary url .tryChain { updateProgress(SIGNALING_VIDEO_UPLOAD) } .chain { signalVideoUpload(it.remoteId?.id) } // another safe api call .tryChain { updateProgress(FINISHED) } .also { cleanupFiles() } // also (from kotlin) makes the result cleanup on fail too, unlike tryChain .log() .fold( onSuccess = { Result.success(workDataOf(RESULT_SHARE_URL to it.url)) }, onError = { Result.failure() } ) // and folding to worker result. Profit! fun RemoteGame.getRemoteId() = ApiResult(this.remoteId?.id) .errorOnNull() .map(GameId::Remote) // we're using suspend result to wrap the upload progress private suspend fun uploadVideo(url: String, videoUri: Uri) = SuspendResult { api.uploadVideo( url = url, file = getVideoFile(videoUri), progressCallback = { progress -> // suspend result allowed us to launch nested coroutines and wait for their completion easily launch { updateProgress( state = UPLOADING_VIDEO, currentStateProgress = progress ) } } ) }.log() private suspend fun signalVideoUpload(gameId: String?) = ApiResult(gameId) // starting with a nullable game id .requireNotNull() // and then failing if it was not found, before executing any database calls .tryMap { api.signalUploadedVideo(it) } // and then making a safe api call .log() private enum class WorkerProgressState { POSTING_GAME_DATA, GETTING_VIDEO_URLS, UPLOADING_VIDEO, SIGNALING_VIDEO_UPLOAD, FINISHED } } ``` -------------------------------- ### ApiResult Coroutine and Flow Operators Source: https://github.com/respawn-app/apiresult/blob/master/docs/quickstart.md Operators for integrating `ApiResult` with Kotlin Coroutines and Flows, enabling asynchronous operations and reactive streams. ```APIDOC SuspendResult { }: Description: An ApiResult builder that takes a suspending block, allowing coroutines to be launched inside and exceptions handled. ApiResult.flow { suspendingCall() }: Description: Emits Loading first, then executes the call and emits its result. Flow.asApiResult(): Description: Transforms this flow into another, where Loading is emitted first, then Success or Error based on exceptions. The resulting flow will not throw unless other operators are applied. mapResults { it.transform() }: Description: Maps Success value of a flow of results. rethrowCancellation(): Description: Operator used when a CancellationException may have accidentally been wrapped. ApiResult does not wrap cancellation exceptions. onEachResult { action() }: Description: Executes an action on each successful result of the flow. ``` -------------------------------- ### ApiResult Transformation Operators in Kotlin Source: https://github.com/respawn-app/apiresult/blob/master/docs/quickstart.md Illustrates a chain of ApiResult transformation operators such as error handling, recovery, conditional failure, value mapping, filtering, error mapping, and result folding. ```kotlin val state: SubscriptionState = repo.getSubscriptions(userId) .errorOnNull() // map nulls to error states with compile-time safety .recover { emptyList() } // recover from some or all errors .require { securityRepository.isDeviceTrusted() } // conditionally fail the chain .mapValues(::SubscriptionModel) // map list items .filter { it.isPurchased } // filter values .mapError { 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 ``` -------------------------------- ### Kotlin ApiResult Usage Example Source: https://github.com/respawn-app/apiresult/blob/master/README.md Demonstrates how to wrap a computation with ApiResult and then chain multiple operators like errorOnNull, recover, require, mapValues, filter, mapError, then, chain, onError, onEmpty, and fold to handle success and error states declaratively. ```Kotlin // wrap a result of any computation and expose the result class BillingRepository(private val api: RestApi) { suspend fun getSubscriptions() = ApiResult { api.getSubscriptions() } // -> ApiResult? } // 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 { emptyList() } // recover from some or all errors .require { securityRepository.isDeviceTrusted() } // conditionally fail the chain .mapValues(::SubscriptionModel) // map list items .filter { it.isPurchased } // filter .mapError { 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 // ... } ``` -------------------------------- ### ApiResult Collection Operators Source: https://github.com/respawn-app/apiresult/blob/master/docs/quickstart.md Operators for manipulating collections contained within an `ApiResult` object, such as mapping, filtering, and merging results. ```APIDOC mapValues { item -> item.transform() }: Description: Maps collection values of the Success result. onEmpty { block() }: Description: Executes an operation if the result is Success and the collection is empty. orEmpty(): Description: Returns an empty collection if this result is an Error or Loading. errorIfEmpty(): Description: Transforms this result into an Error if the collection is empty. mapResults { it.toModel() }: Description: Maps all successful results of a collection of results. mapErrors { e -> CustomException(e) }: Description: Maps all errors of a collection of results. filter { it.isValid }: Description: Filters each value of a collection within a successful result. filterErrors(): Description: Returns a list that contains only Error results from a collection of results. filterSuccesses(): Description: Returns a list that contains only Success results from a collection of results. filterNotNull(): Description: Returns a collection where each Success result is returned only if its value is not null. merge(): Description: Merges all Success results into a list, or returns an Error if any result failed. merge(vararg results: ApiResult): Description: Same as 'merge', but for arbitrary parameters. values(): Description: Returns a list of values from Success results, discarding Error or Loading results. firstSuccess(): Description: Returns the first Success value from a collection of results, or an Error if not present. firstSuccessOrNull(): Description: Returns the first success value or null if not present. firstSuccessOrThrow(): Description: Returns the first success value or throws an exception if not present. ``` -------------------------------- ### ApiResult Transform Operators Source: https://github.com/respawn-app/apiresult/blob/master/docs/quickstart.md Operators for transforming the value or state of an `ApiResult` object, including mapping, chaining, error handling, and recovery from exceptions. ```APIDOC unwrap(): Description: Unwraps a nested ApiResult (ApiResult>) to flatten its structure. then { anotherCall(it) } / flatMap(): Description: Executes another ApiResult call and continues with its result type. chain { anotherCall(it) }: Description: Executes another ApiResult call, but discards its Success result and continues with the previous result. map { it.transform() }: Description: Maps Success result values to another type. tryMap { it.transformOrThrow() }: Description: Maps Success result values, catching exceptions thrown in the transform block. Similar to 'then' but for calls not returning an ApiResult. mapError { e -> CustomException(cause = e) }: Description: Maps Error values to another exception type. mapLoading { null }: Description: Maps Loading values to a new state. mapEither(success = { it.toModel() }, error { e -> CustomException() }): Description: Maps both Success and Error results. Loading state is unaffected. mapOrDefault(default = { null }, { it.toModel() }): Description: Maps the value and returns it if the result is Success; otherwise, returns the default value. errorIf { it.isInvalid }: Description: Transforms the result into an Error if the provided predicate is true. errorUnless { it.isAuthorized }: Description: Transforms the result into an Error if the provided condition is false. errorOnNull(): Description: Transforms the result into an Error if the success value is null. errorOnLoading(): Description: Transforms the result into an Error if it is in the Loading state. require(): Description: Throws an exception if the result is an Error or Loading, otherwise returns Success. require { condition() }: Description: Alias for 'errorUnless'. requireNotNull(): Description: Requires that the Success value is non-null. nullOnError(): Description: Returns Success if the result is an Error, otherwise preserves the original Success value. recover { e -> e.defaultValue }: Description: Recovers from all exceptions by applying a recovery block. recover { e -> e.defaultValue }: Description: Recovers from a specific exception type. recoverIf(condition = { it.isRecoverable }, block = { null }): Description: Recovers from an exception if a given condition is met. tryRecover { it.defaultValueOrThrow() }: Description: Recovers from an exception, but if the recovery block throws, wraps the new exception and continues. tryChain { anotherCallOrThrow(it) }: Description: Chains another call that can throw an exception, wrapping the error if it does. Useful when the chained call does not return an ApiResult. mapErrorToCause(): Description: Maps errors to their causes if present; otherwise, returns the original exception. unit(): Description: Discards the value of the result. Equivalent to 'map { Unit }'. ``` -------------------------------- ### Run Pre-Push Gradle Tasks Source: https://github.com/respawn-app/apiresult/blob/master/docs/CONTRIBUTING.md Commands to execute before pushing changes to ensure code quality, successful assembly, and passing all tests. These tasks help maintain code standards and project stability. ```shell gradle detektFormat gradle assemble gradle allTests ``` -------------------------------- ### Configure Local Properties for Project Build Source: https://github.com/respawn-app/apiresult/blob/master/docs/CONTRIBUTING.md Defines essential properties required for building the project, including Sonatype credentials for publishing (optional) and the Android SDK directory (always required). The 'release' flag controls build type. ```properties # only required for publishing sonatypeUsername=... sonatypePassword=... signing.key=... signing.password=... # always required sdk.dir=... release=false ``` -------------------------------- ### JavaScript Docsify Site Configuration Source: https://github.com/respawn-app/apiresult/blob/master/docs/index.html Configures the Docsify documentation site with various settings such as the project name, repository URL, sidebar and navbar loading behavior, automatic header generation, and maximum navigation level. It also defines social sharing options and integrates a plugin for Prism.js to highlight code snippets. ```javascript window.$docsify = { name: 'ApiResult', repo: 'https://github.com/respawn-app/ApiResult', loadSidebar: false, executeScript: true, autoHeader: true, auto2top: true, loadNavbar: true, mergeNavbar: true, maxLevel: 3, relativePath: true, nativeEmoji: true, themeColor: '#00d46a', share: { reddit: true, linkedin: true, facebook: false, twitter: true, whatsapp: false, telegram: true, }, search: { maxAge: 86400000, depth: 6, paths: 'auto', }, plugins: [ function (hook, vm) { hook.doneEach(function (html) { Prism.highlightAll() }) } ] } ``` -------------------------------- ### Apache License 2.0 for Respawn Project Source: https://github.com/respawn-app/apiresult/blob/master/README.md This snippet provides the complete text of the Apache License, Version 2.0, governing the use, reproduction, and distribution of software by the Respawn Team and its contributors. It specifies the rights and limitations for users. ```License Copyright 2022-2025 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. ``` -------------------------------- ### JavaScript Service Worker Registration Source: https://github.com/respawn-app/apiresult/blob/master/docs/index.html Registers a service worker script ('sw.js') for the documentation site. This enables progressive web app features such as offline access and improved performance through caching, provided the user's browser supports service workers. ```javascript if (typeof navigator.serviceWorker !== 'undefined') { navigator.serviceWorker.register('sw.js') } ``` -------------------------------- ### Add ApiResult Dependency (Kotlin DSL) Source: https://github.com/respawn-app/apiresult/blob/master/README.md Shows how to declare the apiresult:core dependency in a Kotlin DSL build.gradle.kts file, recommending commonMainApi for exposing types in module APIs. ```Kotlin 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:") } ``` -------------------------------- ### Add ApiResult Dependency (TOML) Source: https://github.com/respawn-app/apiresult/blob/master/README.md Provides the TOML configuration for adding the apiresult:core dependency to a Gradle project, typically in a versions.toml file. ```TOML [versions] apiresult = "< Badge above 👆️ >" [dependencies] apiresult = { module = "pro.respawn.apiresult:core", version.ref = "apiresult" } ``` -------------------------------- ### CSS Styling for ApiResult Docsify Theme Source: https://github.com/respawn-app/apiresult/blob/master/docs/index.html Defines custom CSS variables and styles for the ApiResult Docsify theme. This includes setting the content maximum width, theme colors, and specific styles for elements like the application name, version selector, and alerts to override default appearances. ```css ApiResult :root { --content-max-width: 70em; --code-inline-color: var(--theme-color); --theme-color: #00d46a; } /* custom theme overrides for versioned plugin*/ .app-name { display: block; margin-bottom: 10px; text-align: center; } .version-selector { display: inline-flex; align-items: center; justify-content: center; margin: 15px auto 10px; } /* Version selector label */ .version-selector-label { margin-right: 10px; } /* Version selector dropdown */ .version-selector select { font-size: 14px; padding: 4px 8px; color: var(--theme-color); background-color: var(--background-color); border: 1px solid var(--theme-color); cursor: pointer; border-radius: 2px; max-width: 200px; width: 100%; } .version-selector select:focus { outline: none; border-color: var(--selection-color); } .alert.flat { background-color: var(--background-color); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.