You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
You can effectively handling`ApiResponse` using the following extensions:
185
+
You can effectively handle`ApiResponse` using the following extensions:
186
186
187
187
-**onSuccess**: Executes when the `ApiResponse` is of type `ApiResponse.Success`. Within this scope, you can directly access the body data.
188
-
-**onError**: Executes when the `ApiResponse` is of type `ApiResponse.Failure.Error`. Here, you can access the `messareOrNull` and `payload` here.
189
-
-**onException**: Executes when the `ApiResponse` is of type `ApiResponse.Failure.Exception`. You can access the `messareOrNull` and `exception` here.
190
-
-**onFailure**: Executes when the `ApiResponse` is either `ApiResponse.Failure.Error` or `ApiResponse.Failure.Exception`. You can access the `messareOrNull` here.
188
+
-**onError**: Executes when the `ApiResponse` is of type `ApiResponse.Failure.Error`. You can access `messageOrNull` and `payload` here.
189
+
-**onException**: Executes when the `ApiResponse` is of type `ApiResponse.Failure.Exception`. You can access `messageOrNull` and `exception` here.
190
+
-**onFailure**: Executes when the `ApiResponse` is either `ApiResponse.Failure.Error` or `ApiResponse.Failure.Exception`. You can access `messageOrNull` here.
191
191
192
192
Each scope operates according to its corresponding `ApiResponse` type:
Sandwich provides a variety of functional extensions for transforming and composing `ApiResponse`:
276
+
277
+
-**Recovery**: `recover`, `recoverWith` - Transform failures back into successes with fallback data
278
+
-**Validation**: `validate`, `requireNotNull` - Validate success data and convert it to failure if invalid
279
+
-**Filter**: `filter`, `filterNot` - Filter items in list data within a successful response
280
+
-**Zip/Combine**: `zip`, `zip3` - Combine multiple `ApiResponse` instances into one
281
+
-**Peek/Tap**: `peek`, `peekSuccess`, `peekFailure`, `peekError`, `peekException` - Observe responses without modifying them
282
+
283
+
```kotlin
284
+
val response = disneyService.fetchDisneyPosterList()
285
+
.validate({ it.isNotEmpty() }) { "List cannot be empty" } // Validate data
286
+
.filter { poster -> poster.isActive } // Filter list items
287
+
.recover(emptyList()) // Recover with fallback
288
+
.peekSuccess { posters -> analytics.track(posters.size) } // Side effects
289
+
```
290
+
291
+
All extensions have corresponding `suspend` variants (e.g., `suspendRecover`, `suspendValidate`) for coroutine support. For comprehensive details, refer to the [ApiResponse documentation](https://skydoves.github.io/sandwich/apiresponse/).
292
+
273
293
### Retrieving
274
294
275
295
Sandwich provides effortless methods to directly extract the encapsulated body data from the `ApiResponse`. You can take advantage of the following functionalities:
@@ -540,7 +560,7 @@ interface NetworkEntryPoint {
540
560
541
561
##### 2. Provide Global Operator Dependency
542
562
543
-
Next, provide your global operator with Hilt like the exambple below:
563
+
Next, provide your global operator with Hilt like the example below:
You can effectively handling`ApiResponse` using the following extensions:
114
+
You can effectively handle`ApiResponse` using the following extensions:
115
115
116
116
-**onSuccess**: Executes when the `ApiResponse` is of type `ApiResponse.Success`. Within this scope, you can directly access the body data.
117
-
-**onError**: Executes when the `ApiResponse` is of type `ApiResponse.Failure.Error`. Here, you can access the `messareOrNull` and `payload` here.
118
-
-**onException**: Executes when the `ApiResponse` is of type `ApiResponse.Failure.Exception`. You can access the `messareOrNull` and `exception` here.
119
-
-**onFailure**: Executes when the `ApiResponse` is either `ApiResponse.Failure.Error` or `ApiResponse.Failure.Exception`. You can access the `messareOrNull` here.
117
+
-**onError**: Executes when the `ApiResponse` is of type `ApiResponse.Failure.Error`. You can access `messageOrNull` and `payload` here.
118
+
-**onException**: Executes when the `ApiResponse` is of type `ApiResponse.Failure.Exception`. You can access `messageOrNull` and `exception` here.
119
+
-**onFailure**: Executes when the `ApiResponse` is either `ApiResponse.Failure.Error` or `ApiResponse.Failure.Exception`. You can access `messageOrNull` here.
120
120
121
121
Each scope operates according to its corresponding `ApiResponse` type:
Sandwich provides recovery extensions to transform a failed `ApiResponse` back into a successful one with fallback data.
205
+
206
+
### recover
207
+
208
+
Returns an `ApiResponse.Success` with the fallback value if the response is a failure, otherwise returns the original success:
209
+
210
+
```kotlin
211
+
val response = disneyService.fetchDisneyPosterList()
212
+
.recover(emptyList()) // Returns empty list if the request fails
213
+
214
+
// With a lambda for lazy evaluation
215
+
val response = disneyService.fetchDisneyPosterList()
216
+
.recover { cachedPosters }
217
+
```
218
+
219
+
### recoverWith
220
+
221
+
Recovers the failure by executing an alternative `ApiResponse`:
222
+
223
+
```kotlin
224
+
val response = disneyService.fetchDisneyPosterList()
225
+
.recoverWith { failure ->
226
+
// Try an alternative data source on failure
227
+
localDatabase.fetchCachedPosters()
228
+
}
229
+
```
230
+
231
+
For coroutines, use `suspendRecover` and `suspendRecoverWith`:
232
+
233
+
```kotlin
234
+
val response = disneyService.fetchDisneyPosterList()
235
+
.suspendRecoverWith { failure ->
236
+
backupService.fetchPosters() // suspend function
237
+
}
238
+
```
239
+
240
+
## Validation
241
+
242
+
Validation extensions allow you to validate success data and convert it to a failure if the validation fails.
243
+
244
+
### validate
245
+
246
+
Validates the success data with a predicate. If the predicate returns false, the response is converted to `ApiResponse.Failure.Error`:
247
+
248
+
```kotlin
249
+
val response = disneyService.fetchDisneyPosterList()
250
+
.validate(
251
+
predicate = { it.isNotEmpty() },
252
+
errorMessage = { "Poster list cannot be empty" }
253
+
)
254
+
```
255
+
256
+
### requireNotNull
257
+
258
+
Requires a non-null value from the success data. If the selected value is null, the response is converted to `ApiResponse.Failure.Error`:
259
+
260
+
```kotlin
261
+
val response = userService.fetchUser()
262
+
.requireNotNull(
263
+
selector = { it.profileImage },
264
+
errorMessage = { "Profile image is required" }
265
+
)
266
+
```
267
+
268
+
For coroutines, use `suspendValidate` and `suspendRequireNotNull`:
269
+
270
+
```kotlin
271
+
val response = userService.fetchUser()
272
+
.suspendValidate { user ->
273
+
userValidator.isValid(user) // suspend function
274
+
}
275
+
```
276
+
277
+
## Filter
278
+
279
+
Filter extensions allow you to filter items in list data within an `ApiResponse`.
280
+
281
+
### filter
282
+
283
+
Filters the items in the success data list, keeping only items that match the predicate:
284
+
285
+
```kotlin
286
+
val response = disneyService.fetchDisneyPosterList()
287
+
.filter { poster -> poster.isActive }
288
+
```
289
+
290
+
### filterNot
291
+
292
+
Filters the items in the success data list, excluding items that match the predicate:
293
+
294
+
```kotlin
295
+
val response = disneyService.fetchDisneyPosterList()
296
+
.filterNot { poster -> poster.isDeprecated }
297
+
```
298
+
299
+
For coroutines, use `suspendFilter` and `suspendFilterNot`:
300
+
301
+
```kotlin
302
+
val response = disneyService.fetchDisneyPosterList()
303
+
.suspendFilter { poster ->
304
+
posterValidator.isValid(poster) // suspend function
305
+
}
306
+
```
307
+
308
+
## Zip / Combine
309
+
310
+
Zip extensions allow you to combine multiple `ApiResponse` instances into a single response.
311
+
312
+
### zip
313
+
314
+
Combines two `ApiResponse` instances. If both are successful, the transform function is applied. If either is a failure, the first failure is returned:
315
+
316
+
```kotlin
317
+
val usersResponse = userService.fetchUsers()
318
+
val postersResponse = disneyService.fetchPosters()
319
+
320
+
val combined = usersResponse.zip(postersResponse) { users, posters ->
321
+
HomeData(users = users, posters = posters)
322
+
}
323
+
324
+
// Or combine into a Pair
325
+
val paired = usersResponse.zip(postersResponse) // Returns ApiResponse<Pair<Users, Posters>>
326
+
```
327
+
328
+
### zip3
329
+
330
+
Combines three `ApiResponse` instances:
331
+
332
+
```kotlin
333
+
val response1 = service.fetchUsers()
334
+
val response2 = service.fetchPosters()
335
+
val response3 = service.fetchSettings()
336
+
337
+
val combined = response1.zip3(response2, response3) { users, posters, settings ->
0 commit comments