I am learning retrofit and cannot understand what is Call<> in that means.
Even the docs are too hard to understand.
Can someone give a clear explanation on this?
Think of Call as a simple class which wraps your API response and you need this class make an API call and provide listeners/callback to notify you with error and response , although if you use kotlin coroutines then after version 2.6.0 or retrofit you can totally abandon Call , you can directly return response from the function and you don't need any callback which is very clean.
do if like
#GET("users/{id}")
suspend fun user(#Path("id") id: Long): User
or
#GET("users/{id}")
suspend fun user(#Path("id") id: Long): Response<User>
Call is a method to request to the webserver/API to get data.(Based on my understanding)
Related
I am trying to understand how retrofit implements the following suspend function:
#GET("api/me")
suspend fun getUser(): User
Is there anyway that I can access the locally generated implementation code?
Thanks!
According to docs,
Behind the scenes this behaves as if defined as fun user(...):
Call and then invoked with Call.enqueue. You can also return
Response for access to the response metadata.
Everything else lies inside the sources like this class. Btw, I'm just curious, why do you need to understand the exact implementation from the Retrofit side?
I am trying to make a request in my android project. The url is this one
"https://api.spoonacular.com/recipes/716429/information?includeNutrition=false"
I am using retrofit 2 but i can't figure out how to make it work.
Here is what i tried to do.
I get the id of a recipe and call this function passing the id.
fun applyQueryById(recipeId: Int): String{
val searchByIdQuery = "${recipeId}/information?includeNutrition=false&apiKey=${API_KEY}"
return searchByIdQuery
}
And the GET request is this one
#GET("/recipes/")
suspend fun getRecipeById(
#Query("id") searchById:String
):Response<PersonalizedRecipeResult>
I thinks that because the id is in the middle, making a raw string like i am doing is not a good idea. if anyone could suggest something different I'll appreciate
You are using #Query("id") which will ad the value as query.
From your example, I can see that you want to use #Path
You can use it like this
#GET("/recipes/{id}")
suspend fun getRecipeById(
#Path("id") searchById:String
):Response<PersonalizedRecipeResult>
by this way the searchById will be replaced with {id} in your example call
I'm using retrofit to generate the POST requests in my simple API call:
interface IRetrofitCommService {
#POST("pushnotifications/{entityId}")
suspend fun getNotificationsAsync(
#Path("entityId") entityId: Long,
#Body model: GetNotificationsDto
): Response<List<NotificationData>>
#POST("pushnotifications")
suspend fun registerDeviceAsync(#Body model: RegisterEntityDto):
Response<RegisterEntityResultDto>
}
Note that in the second call, I have only 1 parameter, which is marked with the #Body annotation.
Yet, when I try to use the web call, I get this exception: No annotation found for param 2
Here is my factory for creating the call:
object RetrofitFactory {
const val BASE_URL = "https://localhost:5051/api/"
fun createService(): IRetrofitCommService {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(IRetrofitCommService::class.java)
}
}
Here is the DTO in question:
data class RegisterEntityDto(val name: String, val eventType: Short, val clientId: String)
Why is it looking for a 2nd parameter then? What am I missing?
I'm not very familiar with the Retrofit and I'm doing an educated guess here, but after a short discussion in comments it seems my understanding is actually correct.
Internally, suspend functions in Kotlin receive additional Continuation parameter. It is always the last parameter and it is hidden from the Kotlin code. However, if we look into the generated bytecode, we'll see registerDeviceAsync() function actually receives 2 parameters.
If some tool we use is not aware of suspend functions, it won't be able to properly interpret this additional parameter. It will just "think" registerDeviceAsync() has two params. Retrofit added support for suspend functions in version 2.6.0, so I guess if using older versions with suspend functions we will get exactly the behavior you faced.
You just need to update Retrofit to newer version.
I have a problem using retrofit with rxandroid.
I've created a custom converter as below:
class CustomResponseConverter<T>(private val converter: Converter<ResponseBody, *>): Converter<ResponseBody, T> {
override fun convert(value: ResponseBody): T? {
// custom convert response here
}
}
It's all working fine when i'm returning Single like this:
#GET("route")
fun simpleFetch(): Single<FetchData>
but when i try returning Completable like this:
#GET("route")
fun simpleFetch(): Completable
I found that the convert function doesn't get call. Please help.
Thanks in advance.
For anyone who's running into the same case as me, apparently according to retrofit team here:
Using Completable bypasses all converters, yes, and simply closes the response body so it is consumed. Since there is nowhere for the converted body to go with a Completable, there is no need to call it and perform conversion.
So I guess we'll just keep using Single on this case.
Within an Android app, I'm trying to use Fuel to make an HTTP request within a Kotlin coroutine. My first try is to use the synchronous mode inside a wrapper like this:
launch(UI) {
val token = getToken()
println(token)
}
suspend fun getToken(): String? {
var (request, response, result = TOKEN_URL.httpGet().responseString()
return result.get()
}
But that is returning an android.os.NetworkOnMainThreadException. The Fuel documentation mentions .await() and .awaitString() extensions but I haven't figured it out.
What is the best way to make a Fuel http request within a Kotlin coroutine from the main UI thread in an Android application? Stuck on this - many thanks...
Calling blocking code from a suspend fun doesn't automagically turn it into suspending code. The function you call must already be a suspend fun itself. But, as you already noted, Fuel has first-class support for Kotlin coroutines so you don't have to write it yourself.
I've studied Fuel's test code:
Fuel.get("/uuid").awaitStringResponse().third
.fold({ data ->
assertTrue(data.isNotEmpty())
assertTrue(data.contains("uuid"))
}, { error ->
fail("This test should pass but got an error: ${error.message}")
})
This should be enough to get you going. For example, you might write a simple function as follows:
suspend fun getToken() = TOKEN_URL.httpGet().awaitStringResponse().third
From the documentation "to start a coroutine, there must be at least one suspending function, and it is usually a suspending lambda"
Try this:
async {
val token = getToken()
println(token)
}