Releases: skydoves/sandwich
Release list
2.4.0
New artifacts
sandwich-bom: a Bill of Materials that aligns the versions of every Sandwich artifact.sandwich-ktor-serialization:deserializeErrorBodyandonErrorDeserializefor Ktor, which previously existed only for Retrofit on the JVM.
implementation(platform("com.github.skydoves:sandwich-bom:2.4.0"))
implementation("com.github.skydoves:sandwich")
implementation("com.github.skydoves:sandwich-retrofit")
testImplementation("com.github.skydoves:sandwich-test")Behaviour changes to read before upgrading
Global configuration now works on Kotlin/Native. SandwichInitializer was annotated with @ThreadLocal, which gave every Native thread its own copy of the object state. An operator registered during startup on the main thread was invisible to a request completing on a background thread, so global operators, failure mappers, successCodeRange and sandwichTimeout silently did nothing on iOS and macOS. They now run. If your app registers a global operator such as a token refresher, it will start firing on those platforms for the first time.
SandwichInitializer is now shared across threads. Write it once during application startup and only read it afterwards. Mutating it while requests are in flight is not synchronized.
Global operators no longer re-run on every transformation. mapSuccess, suspendMapSuccess, mapFailure, suspendMapFailure and merge created their result through ApiResponse.of, which re-entered the global pipeline. A three step mapSuccess chain fired a global operator four times, and a global failure mapper applied twice. Each now runs exactly once per request.
mapSuccess no longer captures CancellationException. It rethrows it, so coroutine cancellation propagates instead of being turned into a failed response.
Envelope support
Many backends answer HTTP 200 while the body encodes a business failure. Implementing ApiEnvelope lets Sandwich classify that as ApiResponse.Failure.Error, and unwrap flattens the payload.
data class BaseResponse<T>(val code: Int, val message: String, val data: T?) :
ApiEnvelope<T?, String> {
override val isEnvelopeSuccessful: Boolean get() = code == 0
override val envelopeBody: T? get() = data
override val envelopeError: String get() = message
}
suspend fun posters(): ApiResponse<List<Poster>?> = service.fetchPosters().unwrap()ApiEnvelopeSpec covers models that cannot be modified. A body that does not implement ApiEnvelope is untouched, so this is inert for existing models. Resolves the pattern reported in #30, #38, #85 and #138.
Flow operators
fun posters(): Flow<ApiResponse<List<Poster>>> = apiResponseFlow {
service.fetchPosters()
}.flowOn(Dispatchers.IO)
posters()
.onSuccess { posterDao.insert(data) }
.onError { logger.warn(message()) }
.mapSuccess { map(Poster::toUiModel) }
.foldToFlow(
onSuccess = { UiState.Content(it) },
onFailure = { UiState.Error(it) },
)Also onException, onFailure, mapToDataOrNull and filterSuccessData.
Retry policies
RetryPolicy had no implementations, so everyone wrote their own.
RetryPolicies.none()
RetryPolicies.fixedDelay(maxAttempts = 3, delayMillis = 1_000)
RetryPolicies.linear(maxAttempts = 3, delayMillis = 1_000, maxDelayMillis = 10_000)
RetryPolicies.exponentialBackoff(maxAttempts = 4, factor = 2.0, jitter = 0.5)runAndRetry gains a retryOn predicate that receives the failure, so a 400 is no longer retried like a timeout. Both integrations expose the Retry-After header as retryAfterMillis.
Exception classification
Telling a timeout apart from a connectivity failure meant inspecting the raw throwable, which is platform specific.
SandwichInitializer.sandwichExceptionClassifiers += KtorExceptionClassifier
// or RetrofitExceptionClassifier
response.onException {
when (sandwichException) {
is SandwichTimeoutException -> retryLater()
is SandwichNetworkException -> showOfflineBanner()
else -> report(throwable)
}
}isTimeout, isNetworkFailure and isSerializationFailure cover the common checks. Nothing is registered by default.
Platforms
Adds watchos, tvos, linuxX64, linuxArm64 and mingwX64. The klib ABI dump goes from 9 targets to 17. sandwich-ktorfit omits macosX64, watchosX64 and tvosX64 because ktorfit-lib-light does not publish those variants.
Build and verification
CI ran no tests at all before this release. A test job now runs the 415 unit tests across JVM, Android, macosArm64 and iosSimulatorArm64. klib ABI validation is enabled, so the Native, JS and Wasm surface is guarded. sandwich-test also could not compile for Native, and now does.
Compatibility
No public signature was removed or changed. Every API addition is additive.
2.3.0
2.2.2
What's Changed
- chore(deps): update agp to v9.0.1 by @renovate[bot] in #602
- chore(deps): update dependency com.google.devtools.ksp to v2.3.6 by @renovate[bot] in #603
- fix(deps): update dependency org.mockito:mockito-core to v5.22.0 by @renovate[bot] in #604
- fix(deps): update ktor monorepo to v3.4.1 by @renovate[bot] in #606
- chore(deps): update agp to v9.1.0 by @renovate[bot] in #607
- chore(deps): update gradle to v9.4.0 by @renovate[bot] in #608
- fix(deps): update dependency androidx.core:core-ktx to v1.18.0 by @renovate[bot] in #609
- fix(deps): update dependency com.squareup.okio:okio to v3.17.0 by @renovate[bot] in #610
- fix(deps): update dependency org.mockito:mockito-core to v5.23.0 by @renovate[bot] in #611
- chore(deps): update kotlin, ksp and compose compiler to v2.3.20 by @renovate[bot] in #612
- chore(deps): update gradle to v9.4.1 by @renovate[bot] in #613
- chore(deps): update dependency org.jetbrains.dokka to v2.2.0 by @renovate[bot] in #614
- fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.11.0 by @renovate[bot] in #616
- fix(deps): update ktor monorepo to v3.4.2 by @renovate[bot] in #615
- Introducing a sandwich-testing library by @skydoves in #618
- Prepare to use 2.2.2 by @skydoves in #619
Full Changelog: 2.2.1...2.2.2
2.2.1
What's Changed
- fix(deps): update dependency de.jensklingenberg.ktorfit:ktorfit-ksp to v2.7.2 by @renovate[bot] in #583
- fix(deps): update ktorfit to v2.7.2 by @renovate[bot] in #584
- feat: add JavaScript target support for sandwich-ktor and sandwich-ktorfit by @susheel17 in #586
- chore(deps): update gradle to v9.3.0 by @renovate[bot] in #589
- fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.10.0 by @renovate[bot] in #590
- chore(deps): update actions/setup-java action to v5.2.0 by @renovate[bot] in #591
- chore(deps): update actions/checkout action to v6.0.2 by @renovate[bot] in #593
- fix(deps): update ktor monorepo to v3.4.0 by @renovate[bot] in #592
- chore(deps): update dependency com.google.devtools.ksp to v2.3.5 by @renovate[bot] in #595
- chore(deps): update gradle to v9.3.1 by @renovate[bot] in #596
- chore(deps): update actions/checkout digest to de0fac2 by @renovate[bot] in #597
- Migrate to AGP 9.0 by @skydoves in #598
- chore(deps): update kotlin, ksp and compose compiler to v2.3.10 by @renovate[bot] in #599
- fix: re-throw CancellationException in suspend exception handlers by @susheel17 in #587
- Fix Retrofit swallows the CallcellationException by @skydoves in #600
- fix: properly await ApiResponseFailureSuspendMapper in suspend contexts by @susheel17 in #585
- Implement suspendException and migrate for the suspension calls by @skydoves in #601
New Contributors
- @susheel17 made their first contribution in #586
Full Changelog: 2.2.0...2.2.1
2.2.0
What's Changed
- fix(deps): update androidxlifecycle to v2.9.4 by @renovate[bot] in #538
- chore(deps): update gradle to v9.1.0 by @renovate[bot] in #539
- fix(deps): update dependency org.mockito:mockito-core to v5.20.0 by @renovate[bot] in #540
- chore(deps): update agp to v8.13.0 by @renovate[bot] in #529
- fix(deps): update okhttp monorepo to v5.2.0 by @renovate[bot] in #543
- chore(deps): update dependency com.google.devtools.ksp to v2.2.20-2.0.4 by @renovate[bot] in #544
- Remove accidental empty files and fix ProGuard path by @egor-n in #545
- fix(deps): update ktor monorepo to v3.3.1 by @renovate[bot] in #546
- fix(deps): update dependency com.squareup.okio:okio to v3.16.1 by @renovate[bot] in #547
- fix(deps): update okhttp monorepo to v5.2.1 by @renovate[bot] in #548
- fix(deps): update dependency com.squareup.okio:okio to v3.16.2 by @renovate[bot] in #549
- chore(deps): update dependency org.jetbrains.dokka to v2.1.0 by @renovate[bot] in #550
- chore(deps): update dependency com.google.devtools.ksp to v2.3.0 by @renovate[bot] in #551
- chore(deps): update kotlin, ksp and compose compiler to v2.2.21 by @renovate[bot] in #552
- chore(deps): update gradle to v9.2.0 by @renovate[bot] in #553
- fix(deps): update okhttp monorepo to v5.3.0 by @renovate[bot] in #554
- chore(deps): update dependency com.google.devtools.ksp to v2.3.1 by @renovate[bot] in #555
- chore(deps): update dependency com.google.devtools.ksp to v2.3.2 by @renovate[bot] in #557
- fix(deps): update ktor monorepo to v3.3.2 by @renovate[bot] in #556
- chore(deps): update agp to v8.13.1 by @renovate[bot] in #558
- fix(deps): update dependency com.squareup.okio:okio to v3.16.3 by @renovate[bot] in #559
- fix(deps): update okhttp monorepo to v5.3.1 by @renovate[bot] in #560
- chore(deps): update actions/checkout action to v5.0.1 by @renovate[bot] in #561
- chore(deps): update actions/checkout digest to 93cb6ef by @renovate[bot] in #563
- chore(deps): update gradle to v9.2.1 by @renovate[bot] in #562
- fix(deps): update dependency com.squareup.okio:okio to v3.16.4 by @renovate[bot] in #564
- fix(deps): update okhttp monorepo to v5.3.2 by @renovate[bot] in #565
- chore(deps): update dependency com.google.devtools.ksp to v2.3.3 by @renovate[bot] in #568
- fix(deps): update dependency de.jensklingenberg.ktorfit:ktorfit-ksp to v2.6.5 by @renovate[bot] in #570
- fix(deps): update ktor monorepo to v3.3.3 by @renovate[bot] in #569
- fix(deps): update ktorfit to v2.6.5 by @renovate[bot] in #571
- chore(deps): update actions/setup-java action to v5.1.0 by @renovate[bot] in #572
- fix(deps): update dependency org.mockito:mockito-core to v5.21.0 by @renovate[bot] in #575
- chore(deps): update dependency com.android.test to v8.13.2 by @renovate[bot] in #576
- chore(deps): update actions/cache action to v5 by @renovate[bot] in #577
- chore(deps): update actions/checkout action to v6 by @renovate[bot] in #567
- chore(deps): update dependency com.diffplug.spotless to v8 - autoclosed by @renovate[bot] in #541
- Bump Kotlin to 2.3.0 by @skydoves in #579
- chore(deps): update dependency com.google.devtools.ksp to v2.3.4 by @renovate[bot] in #580
- Add recovery, validation, filter, zip, and peek extensions for ApiResponse by @skydoves in #581
- Prepare for release 2.2.0 by @skydoves in #582
New Contributors
Full Changelog: 2.1.3...2.2.0
2.1.3
What's Changed
- Bump Kotlin to 2.2.10 by @skydoves in #528
- Return explicit message values by @skydoves in #530
- Add Js support for the sandwich package by @skydoves in #531
- fix(deps): update androidxmacrobenchmark to v1.4.1 by @renovate[bot] in #532
- chore(deps): update kotlin, ksp and compose compiler by @renovate[bot] in #486
- chore(deps): update dependency com.google.devtools.ksp to v2.2.20-2.0.3 by @renovate[bot] in #534
- fix(deps): update ktor monorepo to v3.3.0 by @renovate[bot] in #533
- fix(deps): update dependency com.github.bumptech.glide:glide to v5.0.5 by @renovate[bot] in #535
- Fix suspendOf never catch exceptions by @skydoves in #536
- Throw CancellationException on suspendOf functions by @skydoves in #537
Full Changelog: 2.1.2...2.1.3
2.1.2
What's Changed
- chore(deps): update actions/setup-java action to v4.7.1 by @renovate in #459
- fix(deps): update dependency androidx.core:core-ktx to v1.16.0 by @renovate in #460
- fix(deps): update dependency com.squareup.okio:okio to v3.11.0 by @renovate in #461
- chore(deps): update agp to v8.9.2 by @renovate in #462
- chore(deps): update dependency gradle to v8.14 by @renovate in #463
- fix(deps): update ktor monorepo to v3.1.3 by @renovate in #465
- chore(deps): update agp to v8.10.0 by @renovate in #466
- fix(deps): update androidxlifecycle to v2.9.0 by @renovate in #467
- fix(deps): update retrofit monorepo to v2.12.0 by @renovate in #468
- fix(deps): update retrofit monorepo to v3 (major) by @renovate in #469
- fix(deps): update dependency org.mockito:mockito-core to v5.18.0 by @renovate in #470
- chore(deps): update dependency gradle to v8.14.1 by @renovate in #471
- chore(deps): update dependency com.diffplug.spotless to v7.0.4 by @renovate in #473
- fix(deps): update dependency com.squareup.okio:okio to v3.12.0 by @renovate in #474
- chore(deps): update agp to v8.10.1 by @renovate in #475
- Remove redundant casting for the failure check inside the map by @skydoves in #477
- Bump Kotlin, KSP, and ktorfit by @skydoves in #478
Full Changelog: 2.1.1...2.1.2
2.1.1
What's Changed
- chore(deps): update actions/setup-java action to v4.7.0 by @renovate in #438
- fix(deps): update ktor monorepo to v3.1.0 by @renovate in #439
- chore(deps): update kotlin, ksp and compose compiler by @renovate in #436
- chore(deps): update agp to v8.8.1 by @renovate in #440
- chore(deps): update dependency com.google.devtools.ksp to v2.1.10-1.0.30 by @renovate in #441
- fix(deps): update dependency de.jensklingenberg.ktorfit:ktorfit-ksp to v2.2.0-1.0.30 by @renovate in #442
- fix(deps): update ktor monorepo to v3.1.1 by @renovate in #445
- chore(deps): update dependency gradle to v8.13 by @renovate in #446
- chore(deps): update agp to v8.8.2 by @renovate in #447
- chore(deps): update dependency com.google.devtools.ksp to v2.1.10-1.0.31 by @renovate in #448
- fix(deps): update dependency org.mockito:mockito-core to v5.16.0 by @renovate in #449
- chore(deps): update agp to v8.9.0 by @renovate in #450
- fix(deps): update dependency org.mockito:mockito-core to v5.16.1 by @renovate in #451
- chore(deps): update agp to v8.9.1 by @renovate in #453
- fix(deps): update androidxmacrobenchmark to v1.3.4 by @renovate in #454
- fix(deps): update ktor monorepo to v3.1.2 by @renovate in #455
- fix(deps): update dependency org.mockito:mockito-core to v5.17.0 by @renovate in #456
- chore(deps): update dependency com.diffplug.spotless to v7.0.3 by @renovate in #457
- Implement fold and foldSuspend extensions by @skydoves in #458
Full Changelog: 2.1.0...2.1.1
2.1.0
2.0.11
What's Changed
- chore(deps): update agp to v8.7.1 by @renovate in #391
- fix(deps): update dependency org.mockito:mockito-core to v5.14.2 by @renovate in #392
- chore(deps): update androidxmacrobenchmark to v1.3.3 by @renovate in #393
- chore(deps): update actions/checkout digest to 11bd719 by @renovate in #395
- chore(deps): update actions/checkout action to v4.2.2 by @renovate in #396
- chore(deps): update dependency com.google.devtools.ksp to v2.0.21-1.0.26 by @renovate in #397
- chore(deps): update actions/setup-java action to v4.5.0 by @renovate in #398
- fix(deps): update androidxlifecycle to v2.8.7 by @renovate in #401
- fix(deps): update dependency androidx.core:core-ktx to v1.15.0 by @renovate in #402
- fix(deps): update ktor monorepo to v3.0.1 by @renovate in #400
- chore(deps): update agp to v8.7.2 by @renovate in #403
- fix(deps): update dependency de.jensklingenberg.ktorfit:ktorfit-ksp to v2.1.0-1.0.26 by @renovate in #404
- chore(deps): update dependency com.google.devtools.ksp to v2.0.21-1.0.27 by @renovate in #405
- fix(deps): update dependency de.jensklingenberg.ktorfit:ktorfit-ksp to v2.1.0-1.0.27 by @renovate in #406
- fix(deps): update dependency de.jensklingenberg.ktorfit:ktorfit-ksp to v2.2.0-1.0.27 by @renovate in #408
- chore(deps): update dependency gradle to v8.11 by @renovate in #409
- chore(deps): update dependency com.google.devtools.ksp to v2.0.21-1.0.28 by @renovate in #410
- fix(deps): update dependency de.jensklingenberg.ktorfit:ktorfit-ksp to v2.2.0-1.0.28 by @renovate in #411
- chore(deps): update dependency gradle to v8.11.1 by @renovate in #412
- fix(deps): update dependency de.jensklingenberg.ktorfit:ktorfit-ksp to v2.2.0-1.0.29 by @renovate in #416
- chore(deps): update agp to v8.7.3 by @renovate in #417
- fix(deps): update moshi to v1.15.2 by @renovate in #419
- fix(deps): update ktor monorepo to v3.0.2 by @renovate in #418
- chore(deps): update dependency org.jetbrains.dokka to v2 by @renovate in #421
- chore(deps): update actions/setup-java action to v4.6.0 - autoclosed by @renovate in #422
- Update ktorfit.md by @LukasVykuka in #420
- chore(deps): update dependency gradle to v8.12 by @renovate in #424
- fix(deps): update ktor monorepo to v3.0.3 by @renovate in #423
- fix(docs): move retry text block under retry code example by @mvdorian in #425
- fix(deps): update dependency org.mockito:mockito-core to v5.15.2 by @renovate in #427
- chore(deps): update agp to v8.8.0 by @renovate in #430
- Using response in Error for ktorfit converter by @savvasdalkitsis in #432
- chore(deps): update dependency com.diffplug.spotless to v7 - autoclosed by @renovate in #428
- fix(deps): update dependency com.squareup.okio:okio to v3.10.2 by @renovate in #429
- fix(deps): update kotlin, ksp and compose compiler by @renovate in #415
New Contributors
- @LukasVykuka made their first contribution in #420
- @mvdorian made their first contribution in #425
- @savvasdalkitsis made their first contribution in #432
Full Changelog: 2.0.10...2.0.11