-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* (release) v1.4.0
- Loading branch information
Showing
97 changed files
with
2,160 additions
and
677 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
Converters are used to convert the HTTPResponse or parameters. | ||
|
||
They are added inside of a Converter.Factory which will then be added to the Ktorfit builder with the **converterfactories()** function. | ||
|
||
### Converter Types | ||
* [ResponseConverters](./responseconverter.md) | ||
* [SuspendResponseConverter](./suspendresponseconverter.md) | ||
* [RequestParameterConverter](./requestparameterconverter.md) | ||
|
||
### Existing converter factories | ||
* CallConverterFactory | ||
* FlowConverterFactoy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
Let's say you want to get an user from an API and the response you get looks like below: | ||
|
||
```kotlin title="API response" | ||
{ | ||
"success": true, | ||
"user": | ||
{ | ||
"id": 1, | ||
"name": "Jens Klingenberg" | ||
} | ||
} | ||
``` | ||
|
||
But you are only interested in the "user" object, and you want to look your interface function something like this: | ||
|
||
```kotlin title="Example function" | ||
@GET("/user") | ||
suspend fun getUser(): User | ||
``` | ||
|
||
First you need the Kotlin classes to which your JSON data is mapped to: | ||
!!! note "This example assumes that you are Kotlin Serialization" | ||
|
||
```kotlin | ||
@kotlinx.serialization.Serializable | ||
data class Envelope(val success: Boolean, val user: User) | ||
|
||
@kotlinx.serialization.Serializable | ||
data class User(val id: Int, val name: String) | ||
``` | ||
|
||
|
||
Now you need a converter that can convert the HTTPResponse and return a user object. | ||
Create a class that extends Converter.Factory | ||
|
||
```kotlin | ||
class UserFactory : Converter.Factory { | ||
|
||
} | ||
``` | ||
|
||
Because in this case **User** is the return type of a suspend function, you need to create a **SuspendResponseConverter**. Override **suspendResponseConverter()** | ||
|
||
```kotlin | ||
class UserFactory : Converter.Factory { | ||
override fun suspendResponseConverter( | ||
typeData: TypeData, | ||
ktorfit: Ktorfit | ||
): Converter.SuspendResponseConverter<HttpResponse, *>? { | ||
|
||
} | ||
} | ||
``` | ||
|
||
Inside **suspendResponseConverter** you can decide if you want to return a converter. In our case we a converter for the | ||
type User. | ||
We can check that case with the typeData that we get as a parameter. | ||
|
||
```kotlin | ||
override fun suspendResponseConverter( | ||
typeData: TypeData, | ||
ktorfit: Ktorfit | ||
): Converter.SuspendResponseConverter<HttpResponse, *>? { | ||
if (typeData.typeInfo.type == User::class) { | ||
... | ||
} | ||
return null | ||
} | ||
``` | ||
|
||
Next we create the SuspendResponseConverter: | ||
```kotlin | ||
if (typeData.typeInfo.type == User::class) { | ||
return object : Converter.SuspendResponseConverter<HttpResponse, Any> { | ||
override suspend fun convert(response: HttpResponse): Any { | ||
... | ||
} | ||
} | ||
} | ||
|
||
``` | ||
Inside of **convert** we get the HttpResponse and we want to return a User object. | ||
|
||
Now we could do the following: | ||
|
||
When we know that this converter will always be used for a API that wraps the User inside an Envelope class, we can directly transform the body to an envelope object and just return the user object. | ||
|
||
```kotlin | ||
override suspend fun convert(response: HttpResponse): Any { | ||
val envelope = response.body<Envelope>() | ||
return envelope.user | ||
} | ||
``` | ||
|
||
or we can create a TypeData of Envelope and use **nextSuspendResponseConverter()** to look up the next converter that can convert the response | ||
|
||
```kotlin | ||
override suspend fun convert(response: HttpResponse): Any { | ||
val typeData = TypeData.createTypeData("com.example.model.Envelope", typeInfo<Envelope>()) | ||
val envelope = ktorfit.nextSuspendResponseConverter(null, typeData)?.convert(response) as? Envelope | ||
return envelope.user | ||
} | ||
``` | ||
|
||
Finally, add your converter factory to the Ktorfit Builder | ||
|
||
```kotlin | ||
Ktorfit.Builder().converterFactories(UserFactory()).baseUrl("foo").build() | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
* SuspendResponseConverter -> Converter.SuspendResponseConverter | ||
|
||
```kotlin title="SuspendResponseConverter" | ||
override suspend fun <RequestType> wrapSuspendResponse( | ||
typeData: TypeData, | ||
requestFunction: suspend () -> Pair<TypeInfo, HttpResponse>, | ||
ktorfit: Ktorfit | ||
): Any { | ||
return object : Call<RequestType> { | ||
override fun onExecute(callBack: Callback<RequestType>) { | ||
|
||
ktorfit.httpClient.launch { | ||
val deferredResponse = async { requestFunction() } | ||
|
||
val (data, response) = deferredResponse.await() | ||
|
||
try { | ||
val res = response.call.body(data) | ||
callBack.onResponse(res as RequestType, response) | ||
} catch (ex: Exception) { | ||
callBack.onError(ex) | ||
} } } } } | ||
|
||
override fun supportedType(typeData: TypeData, isSuspend: Boolean): Boolean { | ||
return typeData.qualifiedName == "de.jensklingenberg.ktorfit.Call" | ||
} | ||
``` | ||
|
||
|
||
```kotlin title="Equivalent with converter factory:" | ||
public class CallConverterFactory : Converter.Factory { | ||
|
||
override fun suspendResponseConverter( | ||
typeData: TypeData, | ||
ktorfit: Ktorfit | ||
): Converter.SuspendResponseConverter<HttpResponse, *>? { | ||
if (typeData.typeInfo.type == Call::class) { | ||
return object: Converter.SuspendResponseConverter<HttpResponse, Call<Any?>> { | ||
override suspend fun convert(response: HttpResponse): Call<Any?> { | ||
|
||
return object : Call<Any?> { | ||
override fun onExecute(callBack: Callback<Any?>) { | ||
ktorfit.httpClient.launch { | ||
try { | ||
val data = response.call.body(typeData.typeArgs.first().typeInfo) | ||
callBack.onResponse(data!!, response) | ||
} catch (ex: Exception) { | ||
callBack.onError(ex) | ||
} } } } } } | ||
} | ||
return null | ||
} | ||
} | ||
``` | ||
|
||
* ResponseConverter -> Converter.ResponseConverter | ||
|
||
```kotlin title="ResponseConverter" | ||
override fun <RequestType> wrapResponse( | ||
typeData: TypeData, | ||
requestFunction: suspend () -> Pair<TypeInfo, HttpResponse?>, | ||
ktorfit: Ktorfit | ||
): Any { | ||
return object : Call<RequestType> { | ||
override fun onExecute(callBack: Callback<RequestType>) { | ||
|
||
ktorfit.httpClient.launch { | ||
val deferredResponse = async { requestFunction() } | ||
|
||
try { | ||
val (info, response) = deferredResponse.await() | ||
val data = response!!.body(info) as RequestType | ||
callBack.onResponse(data, response) | ||
} catch (ex: Exception) { | ||
callBack.onError(ex) | ||
} | ||
|
||
} | ||
} | ||
|
||
} | ||
} | ||
|
||
override fun supportedType(typeData: TypeData, isSuspend: Boolean): Boolean { | ||
return typeData.qualifiedName == "de.jensklingenberg.ktorfit.Call" | ||
} | ||
``` | ||
|
||
```kotlin title="Equivalent with converter factory:" | ||
public class CallConverterFactory : Converter.Factory { | ||
override fun responseConverter( | ||
typeData: TypeData, | ||
ktorfit: Ktorfit | ||
): Converter.ResponseConverter<HttpResponse, *>? { | ||
if (typeData.typeInfo.type == Call::class) { | ||
return object : Converter.ResponseConverter<HttpResponse, Call<Any?>> { | ||
|
||
override fun convert(getResponse: suspend () -> HttpResponse): Call<Any?> { | ||
return object : Call<Any?> { | ||
override fun onExecute(callBack: Callback<Any?>) { | ||
ktorfit.httpClient.launch { | ||
try { | ||
val response = getResponse() | ||
|
||
val data = response.call.body(typeData.typeArgs.first().typeInfo) | ||
|
||
callBack.onResponse(data, response) | ||
} catch (ex: Exception) { | ||
println(ex) | ||
callBack.onError(ex) | ||
} } } } } } | ||
} | ||
return null | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# RequestParameterConverter | ||
|
||
```kotlin | ||
@GET("posts/{postId}/comments") | ||
suspend fun getCommentsById(@RequestType(Int::class) @Path("postId") postId: String): List<Comment> | ||
``` | ||
|
||
You can set RequestType at a parameter with a type to which the parameter should be converted. | ||
|
||
Then you need to implement a Converter factory with a RequestParameterConverter. | ||
|
||
```kotlin | ||
class StringToIntRequestConverterFactory : Converter.Factory { | ||
override fun requestParameterConverter( | ||
parameterType: KClass<*>, | ||
requestType: KClass<*> | ||
): Converter.RequestParameterConverter? { | ||
return object : Converter.RequestParameterConverter { | ||
override fun convert(data: Any): Any { | ||
//convert the data | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
```kotlin | ||
ktorfit.converterFactories(StringToIntRequestConverterFactory()) | ||
``` |
Oops, something went wrong.