Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/skydoves/retrofit-adapters
🚆 Retrofit call adapters for modeling network responses using Kotlin Result, Jetpack Paging3, and Arrow Either.
https://github.com/skydoves/retrofit-adapters
android arrow-kt coroutines either jetpack kotlin kotlin-result network paging3 retrofit retrofit2
Last synced: 13 days ago
JSON representation
🚆 Retrofit call adapters for modeling network responses using Kotlin Result, Jetpack Paging3, and Arrow Either.
- Host: GitHub
- URL: https://github.com/skydoves/retrofit-adapters
- Owner: skydoves
- License: apache-2.0
- Created: 2022-07-12T12:13:10.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2024-08-14T10:47:34.000Z (3 months ago)
- Last Synced: 2024-10-04T10:10:10.368Z (about 1 month ago)
- Topics: android, arrow-kt, coroutines, either, jetpack, kotlin, kotlin-result, network, paging3, retrofit, retrofit2
- Language: Kotlin
- Homepage:
- Size: 488 KB
- Stars: 505
- Watchers: 9
- Forks: 17
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
Retrofit Adapters
🚆 Retrofit adapters for modeling network responses with Kotlin Result, Jetpack Paging3, and Arrow Either.
## Sandwich
If you're interested in a more specified and lightweight Monad sealed API library for modeling Retrofit responses and handling exceptions, check out [Sandwich](https://github.com/skydoves/sandwich).## Kotlin's Result
This library allows you to model your Retrofit responses with [Kotlin's Result](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-result/) class.
[![Maven Central](https://img.shields.io/maven-central/v/com.github.skydoves/retrofit-adapters-result.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22com.github.skydoves%22%20AND%20a:%22retrofit-adapters-result%22)
Add the dependency below to your **module**'s `build.gradle` file:
```gradle
dependencies {
implementation "com.github.skydoves:retrofit-adapters-result:1.0.12"
}
```### ResultCallAdapterFactory
You can return [Kotlin's Result](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-result/) class to the Retrofit's service methods by setting `ResultCallAdapterFactory` like the below:
```kotlin
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl("BASE_URL")
.addConverterFactory(..)
.addCallAdapterFactory(ResultCallAdapterFactory.create())
.build()
```Then you can return the `Result` class with the suspend keyword.
```kotlin
interface PokemonService {@GET("pokemon")
suspend fun fetchPokemonList(
@Query("limit") limit: Int = 20,
@Query("offset") offset: Int = 0
): Result
}
```Finally, you will get the network response, which is wrapped by the `Result` class like the below:
```kotlin
viewModelScope.launch {
val result = pokemonService.fetchPokemonList()
if (result.isSuccess) {
val data = result.getOrNull()
// handle data
} else {
// handle error case
}
}
```### Empty Content Response
You can confine the response type as Unit when you need to handle empty body (content) API requests like the below:
```kotlin
@POST("/users/info")
suspend fun updateUserInfo(@Body userRequest: UserRequest): Result
```### Unit Tests by Injecting TestScope
You can also inject your custom `CoroutineScope` into the `ResultCallAdapterFactory` and execute network requests on the scope.
```kotlin
val testDispatcher: TestDispatcher = UnconfinedTestDispatcher()
val testScope = TestScope(testDispatcher)
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl("BASE_URL")
.addConverterFactory(..)
.addCallAdapterFactory(ResultCallAdapterFactory.create(testScope))
.build()
```> **Note**: For more information about the Testing coroutines, check out the [Testing Kotlin coroutines on Android](https://developer.android.com/kotlin/coroutines/test).
## Jetpack's Paging
This library allows you to return the paging source, which is parts of the Jetpack's [Paging library](https://developer.android.com/topic/libraries/architecture/paging/v3-overview).
[![Maven Central](https://img.shields.io/maven-central/v/com.github.skydoves/retrofit-adapters-paging.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22com.github.skydoves%22%20AND%20a:%22retrofit-adapters-paging%22)
Add the dependency below to your **module**'s `build.gradle` file:
```gradle
dependencies {
implementation "com.github.skydoves:retrofit-adapters-paging:"
}
```### PagingCallAdapterFactory
You can return Jetpack's [PagingSource](https://developer.android.com/reference/kotlin/androidx/paging/PagingSource) class to the Retrofit's service methods by setting `PagingCallAdapterFactory` like the below:
```kotlin
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl("BASE_URL")
.addConverterFactory(..)
.addCallAdapterFactory(PagingCallAdapterFactory.create())
.build()
```Then you can return the `NetworkPagingSource` class with the `@PagingKeyConfig` and `@PagingKey` annotations:
```kotlin
interface PokemonService {@GET("pokemon")
@PagingKeyConfig(
keySize = 20,
mapper = PokemonPagingMapper::class
)
suspend fun fetchPokemonListAsPagingSource(
@Query("limit") limit: Int = 20,
@PagingKey @Query("offset") offset: Int = 0,
): NetworkPagingSource
}
```### PagingKeyConfig and PagingKey
To return the `NetworkPagingSource` class, you must attach the `@PagingKeyConfig` and `@PagingKey` annotations to your Retrofit's service methods.
- **@PagingKeyConfig**: Contains paging configurations for the network request and delivery them to the call adapter internally. You should set the `keySize` and `mapper` parameters.
- **@PagingKey**: Marks the parameter in the service interface method as the paging key. This parameter will be paged by incrementing the page values continuously.## PagingMapper
You should create a paging mapper class, which extends the `PagingMapper` interface like the below for transforming the original network response to the list of paging items. This class should be used in the `@PagingKeyConfig` annotation.
```kotlin
class PokemonPagingMapper : PagingMapper {override fun map(value: PokemonResponse): List {
return value.results
}
}
```You will get the network response, which is wrapped by the `NetworkPagingSource` class like the below:
```kotlin
viewModelScope.launch {
val pagingSource = pokemonService.fetchPokemonListAsPagingSource()
val pagerFlow = Pager(PagingConfig(pageSize = 20)) { pagingSource }.flow
stateFlow.emitAll(pagerFlow)
}
```Finally, you should call the `submitData` method by your `PagingDataAdapter` to bind the paging data. If you want to learn more about the Jetpack's Paging, check out the [Paging library](https://developer.android.com/topic/libraries/architecture/paging/v3-overview).
## Arrow's Either
This library allows you to model your Retrofit responses with [arrow-kt](https://github.com/arrow-kt/arrow)'s [Either](https://arrow-kt.io/docs/apidocs/arrow-core/arrow.core/-either/) class.
[![Maven Central](https://img.shields.io/maven-central/v/com.github.skydoves/retrofit-adapters-arrow.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22com.github.skydoves%22%20AND%20a:%22retrofit-adapters-arrow%22)
Add the dependency below to your **module**'s `build.gradle` file:
```gradle
dependencies {
implementation "com.github.skydoves:retrofit-adapters-arrow:"
}
```### EitherCallAdapterFactory
You can return [Arrow's Either](https://arrow-kt.io/docs/apidocs/arrow-core/arrow.core/-either/) class to the Retrofit's service methods by setting `EitherCallAdapterFactory` like the below:
```kotlin
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl("BASE_URL")
.addConverterFactory(..)
.addCallAdapterFactory(EitherCallAdapterFactory.create())
.build()
```Then you can return the `Either` class with the suspend keyword.
```kotlin
interface PokemonService {@GET("pokemon")
suspend fun fetchPokemonListAsEither(
@Query("limit") limit: Int = 20,
@Query("offset") offset: Int = 0
): Either
}
```Finally, you will get the network response, which is wrapped by the `Either` class like the below:
```kotlin
viewModelScope.launch {
val either = pokemonService.fetchPokemonListAsEither()
if (either.isRight()) {
val data = either.orNull()
// handle data
} else {
// handle error case
}
}
```### Empty Content Response
You can confine the response type as Unit when you need to handle empty body (content) API requests like the below:
```kotlin
@POST("/users/info")
suspend fun updateUserInfo(@Body userRequest: UserRequest): Either
```### Unit Tests by Injecting TestScope
You can also inject your custom `CoroutineScope` into the `EitherCallAdapterFactory` and execute network requests on the scope.
```kotlin
val testDispatcher: TestDispatcher = UnconfinedTestDispatcher()
val testScope = TestScope(testDispatcher)
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl("BASE_URL")
.addConverterFactory(..)
.addCallAdapterFactory(EitherCallAdapterFactory.create(testScope))
.build()
```> **Note**: For more information about the Testing coroutines, check out the [Testing Kotlin coroutines on Android](https://developer.android.com/kotlin/coroutines/test).
## Kotlin Serialization
This library allows you to deserialize your error body of the Retrofit response as your custom error class with [Kotlin's Serialization](https://kotlinlang.org/docs/serialization.html).
> For more information about setting up the plugin and dependency, check out [Kotlin's Serialization](https://kotlinlang.org/docs/serialization.html).
[![Maven Central](https://img.shields.io/maven-central/v/com.github.skydoves/retrofit-adapters-serialization.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22com.github.skydoves%22%20AND%20a:%22retrofit-adapters-serialization%22)
Add the dependency below to your **module**'s `build.gradle` file:
```gradle
dependencies {
implementation "com.github.skydoves:retrofit-adapters-serialization:"
}
```### Deserialize Error Body
You can deserialize your error body with the `deserializeHttpError` extension and your custom error class. First, define your custom error class following your RESTful API formats as seen in the below:
```kotlin
@Serializable
public data class ErrorMessage(
val code: Int,
val message: String
)
```Next, gets the result of the error class to the `throwable` instance with the `deserializeHttpError` extension like the below:
```kotlin
val result = pokemonService.fetchPokemonList()
result.onSuccessSuspend {
Timber.d("fetched as Result: $it")
}.onFailureSuspend { throwable ->
val errorBody = throwable.deserializeHttpError()
}
```## Find this repository useful? :heart:
Support it by joining __[stargazers](https://github.com/skydoves/retrofit-adapters/stargazers)__ for this repository. :star:
Also, __[follow me](https://github.com/skydoves)__ on GitHub for my next creations! 🤩# License
```xml
Designed and developed by 2022 skydoves (Jaewoong Eum)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 athttp://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.
```