Skip to content

Commit 7dc7790

Browse files
committed
feat: Update README
1 parent 76123c3 commit 7dc7790

File tree

2 files changed

+141
-131
lines changed

2 files changed

+141
-131
lines changed

README.md

Lines changed: 139 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -8,147 +8,156 @@ A call adapter that handles errors as a part of state
88

99
---
1010

11-
This library provides a Retrofit call adapter for wrapping your API responses in a `NetworkResponse` class using Coroutines.
11+
This library provides a Kotlin Coroutines based Retrofit call adapter for wrapping your API responses in
12+
a `NetworkResponse` type.
1213

1314
## Network Response
1415

15-
`NetworkResponse<S, E>` is a Kotlin sealed class with the following states:
16+
`NetworkResponse<S, E>` is a Kotlin sealed interface with the following states:
1617

17-
1. Success: Represents successful responses (2xx response codes)
18-
2. ServerError: Represents Server errors
19-
3. NetworkError: Represents connectivity errors
20-
4. UnknownError: Represents every other kind of error which can not be classified as an API error or a network problem (eg JSON deserialization exceptions)
18+
1. Success: Represents successful network calls (2xx response codes)
19+
2. Error: Represents unsuccessful network calls
20+
1. ServerError: Server errors (non 2xx responses)
21+
2. NetworkError: IO Errors, connectivity problems
22+
3. UnknownError: Any other errors, like serialization exceptions
2123

22-
It is generic on two types: a response (`S`), and an error (`E`). The response type is your Java/Kotlin representation of the API response, while the error type represents the error response sent by the API.
24+
It is generic on two types: a success response (`S`), and an error response (`E`).
25+
26+
- `S`: Kotlin representation of a successful API response
27+
- `E`: Representation of an unsuccessful API response
2328

2429
## Usage
2530

26-
- Suppose you have an API that returns the following response if the request is successful:
27-
28-
_Successful Response_
29-
30-
```json
31-
{
32-
"name": "John doe",
33-
"age": 21
34-
}
35-
```
36-
37-
- And here's the response when the request was unsuccessful:
38-
39-
_Error Response_
40-
41-
```json
42-
{
43-
"message": "The requested person was not found"
44-
}
45-
```
46-
47-
- You can create two data classes to model the these responses:
48-
49-
```kotlin
50-
data class PersonResponse(val name: String, val age: Int)
51-
data class ErrorResponse(val message: String)
52-
```
53-
54-
- You may then write your API service as:
55-
56-
```kotlin
57-
// APIService.kt
58-
59-
@GET("/person")
60-
fun getPerson(): Deferred<NetworkResponse<PersonResponse, ErrorResponse>>
61-
62-
// or if you want to use Suspending functions
63-
@GET("/person")
64-
suspend fun getPerson(): NetworkResponse<PersonResponse, ErrorResponse>>
65-
```
66-
67-
- Make sure to add this call adapter factory when building your Retrofit instance:
68-
69-
```kotlin
70-
Retrofit.Builder()
71-
.addCallAdapterFactory(NetworkResponseAdapterFactory())
72-
.build()
73-
```
74-
75-
- Then consume the API:
76-
77-
```kotlin
78-
// Repository.kt
79-
80-
suspend fun getPerson() {
81-
val person = apiService.getPerson().await()
82-
// or if you use suspending functions,
83-
val person = apiService.getPerson()
84-
85-
when (person) {
86-
is NetworkResponse.Success -> {
87-
// Handle successful response
88-
}
89-
is NetworkResponse.Error -> {
90-
// Handle error
91-
}
92-
}
93-
94-
// If you care about what type of error
95-
when (person) {
96-
is NetworkResponse.Success -> {
97-
// Handle successful response
98-
}
99-
is NetworkResponse.ServerError -> {
100-
// Handle server error
101-
}
102-
is NetworkResponse.NetworkError -> {
103-
// Handle network error
104-
}
105-
is NetworkResponse.UnknownError -> {
106-
// Handle other errors
107-
}
108-
}
109-
}
110-
```
111-
112-
- You can also use the included utility function `executeWithRetry` to automatically retry your network requests if they result in `NetworkResponse.NetworkError`
113-
114-
```kotlin
115-
suspend fun getPerson() {
116-
val response = executeWithRetry(times = 5) {
117-
apiService.getPerson.await()
118-
}
119-
120-
// or with suspending functions
121-
val response = executeWithRetry(times = 5) {
122-
apiService.getPerson()
123-
}
124-
125-
// Then handle the response
126-
}
127-
```
128-
129-
- There's also an overloaded invoke operator on the NetworkResponse class which returns the success body if the request was successful, or null otherwise
130-
131-
```kotlin
132-
val usersResponse = usersRepo.getUsers().await()
133-
println(usersResponse() ?: "No users were found")
134-
```
135-
136-
- Some API responses convey information through headers only, and contain empty bodies. Such endpoints must be used with `Unit` as their success type.
137-
138-
```kotlin
139-
@GET("/empty-body-endpoint")
140-
suspend fun getEmptyBodyResponse(): NetworkResponse<Unit, ErrorType>
141-
```
31+
Suppose an API returns the following body for a successful response:
32+
33+
_Successful Response_
34+
35+
```json
36+
{
37+
"name": "John doe",
38+
"age": 21
39+
}
40+
```
41+
42+
And this for an unsuccessful response:
43+
44+
_Error Response_
45+
46+
```json
47+
{
48+
"message": "The requested person was not found"
49+
}
50+
```
51+
52+
You can create two data classes to model the these responses:
53+
54+
```kotlin
55+
data class PersonResponse(val name: String, val age: Int)
56+
57+
data class ErrorResponse(val message: String)
58+
```
59+
60+
Then modify your Retrofit service to return a `NetworkResponse`:
61+
62+
```kotlin
63+
@GET("/person")
64+
suspend fun getPerson(): NetworkResponse<PersonResponse, ErrorResponse>>
65+
66+
// You can also request for `Deferred` responses
67+
@GET("/person")
68+
fun getPersonAsync(): Deferred<NetworkResponse<PersonResponse, ErrorResponse>>
69+
```
70+
71+
Finally, add this call adapter factory to your Retrofit instance:
72+
73+
```kotlin
74+
Retrofit.Builder()
75+
.addCallAdapterFactory(NetworkResponseAdapterFactory())
76+
.build()
77+
```
78+
79+
And voila! You can now consume your API as:
80+
81+
```kotlin
82+
// Repository.kt
83+
suspend fun getPerson() {
84+
when (val person = apiService.getPerson()) {
85+
is NetworkResponse.Success -> {
86+
/* Successful response */
87+
}
88+
is NetworkResponse.Error -> {
89+
/* Handle error */
90+
}
91+
}
92+
93+
// Or, if you care about the type of the error:
94+
when (val person = apiService.getPerson()) {
95+
is NetworkResponse.Success -> {
96+
/* ... */
97+
}
98+
is NetworkResponse.ServerError -> {
99+
/* ... */
100+
}
101+
is NetworkResponse.NetworkError -> {
102+
/* ... */
103+
}
104+
is NetworkResponse.UnknownError -> {
105+
/* ... */
106+
}
107+
}
108+
}
109+
```
110+
111+
## Utilities
112+
113+
**Retry Failed Network Calls**
114+
115+
Use the included utility function `executeWithRetry` to automatically retry your network requests if they result in
116+
a `NetworkResponse.NetworkError`
117+
118+
```kotlin
119+
suspend fun getPerson() {
120+
val response = executeWithRetry(times = 5) {
121+
apiService.getPerson()
122+
}
123+
}
124+
```
125+
126+
**Overloaded `invoke()` on `NetworkResponse`**
127+
128+
The `NetworkResponse` interface has an overloaded `invoke()` operator that returns the success body if the request was
129+
successful, or null otherwise
130+
131+
```kotlin
132+
val usersResponse = usersRepo.getUsers()
133+
println(usersResponse() ?: "No users were found")
134+
```
135+
136+
**Handle Empty Response Bodies**
137+
138+
Some API responses convey information through headers only and contain empty bodies. Use `Unit` to represent the success
139+
response type of such network calls.
140+
141+
```kotlin
142+
@DELETE("/person")
143+
suspend fun deletePerson(): NetworkResponse<Unit, ErrorType>
144+
```
142145

143146
---
144147

145148
## Benefits
146149

147-
Modelling errors as a part of your state is a recommended practice. This library helps you deal with scenarios where you can successfully recover from errors, and extract meaningful information from them too!
150+
This library helps you deal with scenarios where you can successfully recover from errors, and extract meaningful
151+
information from them too!
148152

149-
- `NetworkResponseAdapter` provides a much cleaner solution than Retrofit's built in `Call` type for dealing with errors.`Call` throws an exception on any kind of an error, leaving it up to you to catch it and parse it manually to figure out what went wrong. `NetworkResponseAdapter` does all of that for you and returns the result in an easily consumable `NetworkResponse` subtype.
153+
- `NetworkResponseAdapter` provides a much cleaner solution than Retrofit's built in `Call` type for dealing with
154+
errors.`Call` throws an exception on any kind of error, leaving it up to you to catch it and parse it manually to
155+
figure out what went wrong. `NetworkResponseAdapter` does all of that for you and returns the result in an easily
156+
consumable `NetworkResponse` type.
150157

151-
- The RxJava retrofit adapter treats non 2xx response codes as errors, which seems silly in the context of Rx where errors terminate streams. Also, just like the `Call<T>` type, it makes you deal with all types of errors in an `onError` callback, where you have to manually parse it to find out exactly what went wrong.
158+
- The RxJava retrofit adapter treats non 2xx response codes as errors, which seems silly in the context of Rx where
159+
errors terminate streams. Also, just like the `Call<T>` type, it makes you deal with all types of errors in
160+
an `onError` callback, where you have to manually parse it to find out exactly what went wrong.
152161

153162
- Using the `Response` class provided by Retrofit is cumbersome, as you have to manually parse error bodies with it.
154163

@@ -158,17 +167,17 @@ Add the Jitpack repository to your list of repositories:
158167

159168
```groovy
160169
allprojects {
161-
repositories {
162-
maven { url 'https://jitpack.io' }
163-
}
170+
repositories {
171+
maven { url 'https://jitpack.io' }
172+
}
164173
}
165174
```
166175

167176
And then add the dependency in your gradle file:
168177

169178
```groovy
170179
dependencies {
171-
implementation "com.github.haroldadmin:NetworkResponseAdapter:(latest-version)"
180+
implementation "com.github.haroldadmin:NetworkResponseAdapter:(latest-version)"
172181
}
173182
```
174183

src/test/kotlin/com/haroldadmin/cnradapter/NetworkResponseAdapterTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.haroldadmin.cnradapter
22

3-
import com.haroldadmin.cnradapter.utils.*
3+
import com.haroldadmin.cnradapter.utils.CompletableCall
4+
import com.haroldadmin.cnradapter.utils.CrashObjectConversionError
45
import com.haroldadmin.cnradapter.utils.CrashyObject
56
import com.haroldadmin.cnradapter.utils.CrashyObjectConverterFactory
67
import com.haroldadmin.cnradapter.utils.StringConverterFactory

0 commit comments

Comments
 (0)