Skip to content

Commit

Permalink
Merge pull request #376 from markGilchrist/Add_Result_and_object_Impl…
Browse files Browse the repository at this point in the history
…ementations

Add result and object implementations
  • Loading branch information
markGilchrist authored Jul 8, 2018
2 parents e7095ee + 478bdd3 commit e19b7dd
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 165 deletions.
25 changes: 13 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -694,11 +694,11 @@ Fuel.request(WeatherApi.weatherFor("london")).responseJson { request, response,

### Coroutines Support

Coroutines module provides extension functions to wrap a response inside a coroutine and handle its result. The coroutines-based API provides equivalent methods to the standard API (e.g: `responseString()` in coroutines is `awaitString()`).
Coroutines module provides extension functions to wrap a response inside a coroutine and handle its result. The coroutines-based API provides equivalent methods to the standard API (e.g: `awaitStringResponse()` in coroutines is `awaitString()`).

```kotlin
runBlocking {
val (request, response, result) = Fuel.get("https://httpbin.org/ip").awaitString()
val (request, response, result) = Fuel.get("https://httpbin.org/ip").awaitStringResult()

result.fold({ data ->
println(data) // "{"origin":"127.0.0.1"}"
Expand All @@ -708,19 +708,19 @@ runBlocking {
}
```

It also provides useful methods to handle the `Result` value directly. The difference is that they throw exception instead of returning it wrapped a `FuelError` instance.
It also provides useful methods to retrieve the `ByteArray`,`String` or `Object`. The difference with these implementations is that they throw exception instead of returning it wrapped a `FuelError` instance.

```kotlin
runBlocking {
try {
println(Fuel.get("https://httpbin.org/ip").awaitStringResult()) // "{"origin":"127.0.0.1"}"
} catch(exception: HttpException) {
println(Fuel.get("https://httpbin.org/ip").awaitString()) // "{"origin":"127.0.0.1"}"
} catch(exception: Exception) {
println("A network request exception was thrown: ${exception.message}")
}
}
```

Handling objects other than `String` (`awaitString()`) or `ByteArray` (`awaitResponse()`) can be done using `awaitSafelyObjectResult` or `awaitObjectResult`.
Handling objects other than `String` (`awaitString()`) or `ByteArray` (`awaitByteArrayResponse()`) can be done using `awaitObjectResult`

```kotlin
data class Ip(val origin: String)
Expand All @@ -733,7 +733,7 @@ object IpDeserializer : ResponseDeserializable<Ip> {

```kotlin
runBlocking {
Fuel.get("https://httpbin.org/ip").awaitSafelyObjectResult(IpDeserializer)
Fuel.get("https://httpbin.org/ip").awaitObjectResult(IpDeserializer)
.fold({ data ->
println(data.origin) // 127.0.0.1
}, { error ->
Expand All @@ -745,12 +745,13 @@ runBlocking {
```kotlin
runBlocking {
try {
val data = Fuel.get("https://httpbin.org/ip").awaitObjectResult(IpDeserializer)
val data = Fuel.get("https://httpbin.org/ip").awaitObject(IpDeserializer)
println(data.origin) // 127.0.0.1
} catch (exception: HttpException) {
println("A network request exception was thrown: ${exception.message}")
} catch (exception: JsonMappingException) {
println("A serialization/deserialization exception was thrown: ${exception.message}")
} catch (exception: Exception) {
when (exception){
is HttpException -> println("A network request exception was thrown: ${exception.message}")
is JsonMappingException -> println("A serialization/deserialization exception was thrown: ${exception.message}")
else -> println("An error [${exception.javaClass.simpleName}\"] was thrown")
}
}
```
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

import com.github.kittinunf.fuel.core.Deserializable
import com.github.kittinunf.fuel.core.FuelError
import com.github.kittinunf.fuel.core.Request
Expand All @@ -7,7 +8,6 @@ import com.github.kittinunf.fuel.core.Response
import com.github.kittinunf.fuel.core.ResponseDeserializable
import com.github.kittinunf.fuel.core.response
import com.github.kittinunf.result.Result
import com.github.kittinunf.result.mapError
import kotlinx.coroutines.experimental.suspendCancellableCoroutine
import java.nio.charset.Charset

Expand All @@ -19,58 +19,77 @@ private suspend fun <T : Any, U : Deserializable<T>> Request.await(
continuation.resume(response(deserializable))
}

suspend fun Request.awaitResponse(): Triple<Request, Response, Result<ByteArray, FuelError>> =

suspend fun Request.awaitByteArrayResponse(): Triple<Request, Response, Result<ByteArray, FuelError>> =
await(byteArrayDeserializer())

suspend fun Request.awaitString(
suspend fun Request.awaitStringResponse(
charset: Charset = Charsets.UTF_8
): Triple<Request, Response, Result<String, FuelError>> = await(stringDeserializer(charset))

@Deprecated(
replaceWith = ReplaceWith(
expression = ".awaitSafelyObjectResult"),
level = DeprecationLevel.WARNING,
message = "This function cannot handle exceptions properly which causes API inconsistency.")
@Throws
suspend fun <U : Any> Request.awaitObject(
suspend fun <U : Any> Request.awaitObjectResponse(
deserializable: ResponseDeserializable<U>
): Triple<Request, Response, Result<U, FuelError>> = await(deserializable)

/***
*
* Response functions all these return a Type
*
* @return ByteArray if no exceptions are thrown
*/
@Throws
suspend fun Request.awaitResponseResult(): ByteArray = awaitResponse().third
.mapError { throw it.exception }
.get()
suspend fun Request.awaitByteArray(): ByteArray = await(byteArrayDeserializer()).third.get()

/**
* @note errors thrown in deserialization will not be caught
*
* @return ByteArray if no exceptions are thrown
*/
@Throws
suspend fun Request.awaitStringResult(
suspend fun Request.awaitString(
charset: Charset = Charsets.UTF_8
): String = awaitString(charset).third
.mapError { throw it.exception }
.get()
): String = await(stringDeserializer(charset)).third.get()

/**
* This function will throw the an exception if an error is thrown either at the HTTP level
* @note This function will throw the an exception if an error is thrown either at the HTTP level
* or during deserialization
*
* @param deserializable
*
* @return Result object
* */
*/
@Throws
suspend fun <U : Any> Request.awaitObjectResult(
suspend fun <U : Any> Request.awaitObject(
deserializable: ResponseDeserializable<U>
): U = await(deserializable).third
.mapError { throw it.exception }
.get()
): U = await(deserializable).third.get()

/***
*
* Response functions all these return a Result
*
* @return Result<ByteArray,FuelError>
*/
suspend fun Request.awaitByteArrayResult(): Result<ByteArray, FuelError> = awaitByteArrayResponse().third

/**
*
* @param charset this is defaults to UTF-8
*
* @return Result<String,FuelError>
*/
suspend fun Request.awaitStringResult(
charset: Charset = Charsets.UTF_8
): Result<String, FuelError> = awaitStringResponse(charset).third


/**
* This function catches both server errors and Deserialization Errors
*
* @param deserializable
*
* @return Result object
* */
suspend fun <U : Any> Request.awaitSafelyObjectResult(
*/
suspend fun <U : Any> Request.awaitObjectResult(
deserializable: ResponseDeserializable<U>
): Result<U, FuelError> = try {
await(deserializable).third
Expand All @@ -81,3 +100,14 @@ suspend fun <U : Any> Request.awaitSafelyObjectResult(
}
Result.Failure(fuelError)
}

@Deprecated("please use 'awaitByteArray()'", ReplaceWith("awaitByteArray()", "deserializable"))
suspend fun Request.awaitResponseResult(): ByteArray = awaitByteArray()

@Deprecated("please use 'awaitObjectResult(deserializable)'", ReplaceWith("awaitObjectResult(deserializable)"))
suspend fun <U : Any> Request.awaitSafelyObjectResult(
deserializable: ResponseDeserializable<U>
): Result<U, FuelError> = this.awaitObjectResult(deserializable)



Loading

0 comments on commit e19b7dd

Please sign in to comment.