I'm trying to get user name from gitHub Api but retrofit response return always null. When I'm trying to show user name in toast I see : null. I tried change retrofit path but it didn't work. Everything looks fine but I don't know why I get this error all the time.
interface GitHubApi{
#GET("/users/{user}")
fun getUser(#Path("user") user: String): Call<User>
companion object Factory {
fun getClient(): GitHubApi {
val url = "https://api.github.com/"
val interceptor = HttpLoggingInterceptor()
.apply { level = HttpLoggingInterceptor.Level.BODY }
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build()
return retrofit.create(GitHubApi::class.java)
}
}}
user model:
data class User(val userName: String)
MainActivity:
private fun createApiService() : GitHubApi{
val url = "https://api.github.com/"
val interceptor = HttpLoggingInterceptor()
.apply { level = HttpLoggingInterceptor.Level.BODY }
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build()
return retrofit.create(GitHubApi::class.java)
}
private fun loadData() {
val api = GitHubApi.getClient()
api.getUser("fabpot").enqueue(object : Callback<User> {
override fun onFailure(call: Call<User>, t: Throwable) {
t.printStackTrace()
}
override fun onResponse(
call: Call<User>,
response: Response<User>
) {
if (!response.isSuccessful) {
runOnUiThread { showErrorMessage(response.code().toString()) }
}
response.body()?.let { showErrorMessage(it.repoName) }
}
})
}
There is no key userName exist in github api.
try editing your data class this way.
data class User(val name: String)
Try removing the beginning slash "/" in your #GET method.
Related
I used retrofit2 to call API. But, when I called it, my app was just shut down. There are not errors in the Logcat. I googled it, but there is not a solution.
And Retrofit2 and converter-gson version is 2.9.0. I set internet permission in AndroidManifest.xml
MainActivity.kt
private fun loadMembers() {
val retrofit = Retrofit.Builder()
.baseUrl(MemberAPI.base_domain)
.addConverterFactory(GsonConverterFactory.create())
.build()
val retrofitService = retrofit.create(MemberInterface::class.java)
retrofitService
.getMember(Constants.api_key)
.enqueue(object: Callback<Member> {
override fun onResponse(call: Call<Member>, response: Response<Member>) {
val members = response.body() as Member
var names = ""
for (member in members.response.body.items.item) {
names += "\n${member.empNm}"
}
binding.text.text = names
}
override fun onFailure(call: Call<Member>, t: Throwable) {
Toast.makeText(baseContext, "실패", Toast.LENGTH_LONG).show()
}
})
}
Interface.kt
interface MemberInterface {
#GET("{api_key}&numOfRows=5&pageNo=1&_type=json")
fun getMember(#Path("api_key") Key: String): Call<Member>
}
Youtube
Video
Try to add an interceptor so you can see all calls logs (headers, body, URLs, etc...). The crash could be related with the parse of the JSON response to the object Member.
Add OkHtpp to your grade dependencies:
implementation "com.squareup.okhttp3:okhttp:5.0.0-alpha.2"
implementation "com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2"
And after that, when you create your Retrofit instance, add the interceptor, should look something like this:
val httpClient = OkHttpClient.Builder()
val interceptor = HttpLoggingInterceptor()
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
httpClient.addInterceptor(interceptor)
httpClient.addInterceptor(Interceptor { chain: Interceptor.Chain ->
val original: Request = chain.request()
val request: Request = original.newBuilder()
.header("Content-Type", "application/json")
.method(original.method, original.body)
.build()
chain.proceed(request)
})
val okHttpClient = httpClient.build()
val retrofit = Retrofit.Builder()
.baseUrl(MemberAPI.base_domain)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
To access api by Retrofit , Retrofit builder object i am able to use retrofitbuilder object , connect url , build but not able to attach my service class apiInterface which i have created .
private fun getmydata() {
lateinit var myAdapter: RecyclerAdapter
val retrofitBuilder = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(myuri)
.build();
var api : apiInterface = retrofitBuilder.create(apiInterface::class.java)
Error : Create extension property 'KClass.java'
private fun getClient(): Retrofit? {
val interceptor = HttpLoggingInterceptor()
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
val client: OkHttpClient = OkHttpClient.Builder()
.addInterceptor(interceptor)
.retryOnConnectionFailure(true)
.build()
return Retrofit.Builder()
.baseUrl("Your Base URL")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
}
private fun apiCall() {
val firstname = "123"
val lastname = "234"
val email = "345#6.com"
val username = "132456"
val pw = "12345678"
val call = getClient()!!.create(/*Your API Interface Class*/Api::class.java).createUser(
firstname,
lastname,
email,
username,
pw
)
call.enqueue(object : Callback<UserResponse> {
override fun onResponse(call: Call<UserResponse>, response: Response<UserResponse>) {
Toast.makeText(this#MainActivity, response.code().toString()
+ " " + response.body().toString(), Toast.LENGTH_SHORT).show()
}
override fun onFailure(call: Call<UserResponse>, t: Throwable) {
Toast.makeText(this#MainActivity, t.localizedMessage!!.toString(),
Toast.LENGTH_SHORT).show()
}
})
}
I'm trying to learn coroutines with retrofit and hilt.
There is simple api github https://api.github.com/users/JakeWharton/repos
But my code give in log:
D/OkHttp: --> GET https://api.github.com/users/JakeWharton/repos
D/OkHttp: --> END GET
without any reponse, despite the fact that using postman I get list with repos.
In my function loadData() debugger stop on the 1st lane, it doesn't come to println, something is wrong but don't know what.
my codes:
#Provides
fun provideGitHubService(retrofit: Retrofit): GitHubService{
return retrofit.create(GitHubService::class.java)
}
#Provides
fun provideOkHttpClient(): OkHttpClient {
val loggingInterceptor = HttpLoggingInterceptor()
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
return OkHttpClient
.Builder()
.addInterceptor(loggingInterceptor)
.build()
}
#Provides
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
return Retrofit.Builder()
.baseUrl("https://github.com") // don't know how to remove it but it will be override anyway
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build()
}
private fun getRepos() {
viewModelScope.launch {
loadData()
}
}
private suspend fun loadData() {
val response = service.getRepos()
println(response). //debugger doesn't come here
}
interface GitHubService {
#GET("https://api.github.com/users/JakeWharton/repos")
suspend fun getRepos() : Call<List<User>>
}
data class User(
#SerializedName("name") val name: String
)
You don't need Call when using suspend. Please update the getRepos to:
// annotations omitted
suspend fun getRepos() : List<User>
I think you did something wrong in the instance of retrofit. try this.
class User {
#Expose
#SerializedName("name")
var name: String? = null
}
interface GitHubService {
#GET("users/JakeWharton/repos")
suspend fun getRepos(): Call<List<User>>
}
fun provideGitHubService(retrofit: Retrofit): GitHubService{
return retrofit.create(GitHubService::class.java)
}
class Example {
private val TAG = "Example"
/* OKHTTP CLIENT */
private fun provideOkHttpClient(): OkHttpClient {
val loggingInterceptor = HttpLoggingInterceptor()
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
return OkHttpClient
.Builder()
.addInterceptor(loggingInterceptor)
.build()
}
/* RETROFIT INSTANCE */
private fun provideRetrofit(): Retrofit {
return Retrofit.Builder()
.baseUrl("https://api.github.com/") // don't know how to remove it but it will be override anyway
.addConverterFactory(GsonConverterFactory.create())
.client(provideOkHttpClient())
.build()
}
/* LOADING DATA */
suspend fun loadData() {
val apiInterface = provideGitHubService(provideRetrofit())
val call: Call<List<User>> = apiInterface.getRepos()
call.enqueue( object : Callback<List<User>> {
override fun onResponse(call: Call<List<User>>, response: Response<List<User>>) {
for (users in response.body()!!){
Log.e(TAG, "NAME: ${users.name}")
}
}
override fun onFailure(call: Call<List<User>>, t: Throwable) {
Log.e(TAG, "onFailure: ${t.message}")
}
})
}
}
I have ServiceBuilder object for init retrofit instance
object ServiceBuilder {
//private var url: String? = null
var url = "http://no-google.com" // The default link
fun loadUrl(url: String): ServiceBuilder{
this.url = url
return this
}
private var logger = HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
val headerInterceptor = object: Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
request = request.newBuilder()
.addHeader("x-device-type", Build.DEVICE)
.addHeader("Accept-Language", Locale.getDefault().language)
.build()
val response = chain.proceed(request)
return response
}
}
// Create OkHttp Client
private val okHttp = OkHttpClient.Builder()
.callTimeout(5, TimeUnit.SECONDS)
.addInterceptor(headerInterceptor)
.addInterceptor(logger)
// Create Retrofit Builder
private val builder = Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttp.build())
// Create Retrofit Instance
private val retrofit = builder.build()
fun <T> buildService(serviceType: Class<T>): T {
return retrofit.create(serviceType)
}
}
getUrlFromServer() method inside MainActivity
private fun getUrlFromServer(str: String){
val destinationService = ServiceBuilder
.loadUrl("http://google.com") // <-- This call can not reply url into ServiceBuilder object
.buildService(DestinationService::class.java)
val requestCall = destinationService.getList()
requestCall.enqueue(object: Callback<List<Destination>> {
override fun onResponse(
call: Call<List<Destination>>,
response: Response<List<Destination>>
) {
if (response.isSuccessful){
val destinationList = response.body()
//Toast.makeText(this, destinationList.toString(), Toast.LENGTH_LONG)
}
}
override fun onFailure(call: Call<List<Destination>>, t: Throwable) {
TODO("Not yet implemented")
}
})
}
I don't understand why the loadUrl() function which is inside ServiceBuilder can not load url. I need to send url from MainActivity to ServiceBuilder object.
Please tell me how I should decide this issue in good style
Because create retrofit instance, take happen before ServiceBuilder loadUrl function.
Actually retrofit instance, always is created with "http://no-google.com" url!!
fun <T> buildService(serviceType: Class<T>): T {
// Create Retrofit Builder
private val builder = Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttp.build())
// Create Retrofit Instance
private val retrofit = builder.build()
return retrofit.create(serviceType)
}
I am trying to get a response from web service using retrofit and kotlin language. but i am unable to call enque method .
This is retrofit client
class WebService() {
companion object {
fun createService(isAddToken: Boolean): WebServiceApi {
val logging = HttpLoggingInterceptor()
val httpClient = OkHttpClient.Builder()
var retrofit: Retrofit
httpClient.addInterceptor { chain ->
val original = chain.request()
val requestBuilder = original.newBuilder()
.header(CONTENT_TYPE, "application/json")
.header(API_USER_NAME, AUTH_USERNAME)
.header(API_PASSWORD, AUTH_PASSWORD)
.header(LANGUAGE_CODE, "en")
if (isAddToken) {
requestBuilder.header(TOKEN,
"" /*DataGenerator.getAuthToken(context)*/)
}
requestBuilder.method(original.method(), original.body())
val request = requestBuilder.build()
chain.proceed(request)
}
// set your desired log level
if (BuildConfig.DEBUG) {
logging.level = HttpLoggingInterceptor.Level.BODY
// add logging as last interceptor
httpClient.addInterceptor(logging)
}
// Timeout handling
val client = httpClient.readTimeout(20,
TimeUnit.SECONDS)
.connectTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.build()
if (BuildConfig.DEBUG) {
retrofit = Retrofit.Builder()
.baseUrl(WebServiceConstants.LIVE_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
} else {
retrofit = Retrofit.Builder()
.baseUrl(WebServiceConstants.LIVE_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
}
return retrofit.create(WebServiceApi::class.java);
}
}
}
This is code of MainActivity where i am calling api on button
val parameterOTP = SendParameterOTP()
parameterOTP.phoneNumber = phoneNumber
var serviceAPI = WebService.createService(false)
serviceAPI.enque() \\Unable to understand how i call enques**
I tried example using rxjava ,it works fine .But i want to use enque method as i want to implement custom callback for retrying . Please help
try to use this:
val call = createService(isAddToken).methodNameInWebServiceApi(params)
call.enqueue(object : Callback<ResponseObject> {
override fun onFailure(call: Call<ResponseObject>?, t: Throwable?) {
Log.e("erroe", "")
}
override fun onResponse(call: Call<ResponseObject>?, response: Response<ResponseObject>?) {
}
})
i am provide retrofit class and api call using kotlin and make changes according to rxjava in your side.
class ApiClient {
companion object {
val BASE_URL = "https://simplifiedcoding.net/demos/"
var retrofit: Retrofit? = null
fun getClient(): Retrofit? {
if (retrofit == null) {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder().apply {
readTimeout(20, TimeUnit.SECONDS)
writeTimeout(20, TimeUnit.SECONDS)
connectTimeout(20, TimeUnit.SECONDS)
addInterceptor(interceptor)
addInterceptor { chain ->
var request = chain.request()
request = request.newBuilder()
.build()
val response = chain.proceed(request)
response
}
}
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client.build())
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return retrofit
}
}
}
then after used below code for api calling ..
var apiInterface: ApiInterface = ApiClient.getClient()!!.create(ApiInterface::class.java)
var hero: Call<List<Hero>>
hero = apiInterface.getData()
hero.enqueue(object : Callback<List<Hero>> {
override fun onFailure(call: Call<List<Hero>>?, t: Throwable?) {
closeDialog(dialog)
Toast.makeText(mContext, t?.message, Toast.LENGTH_SHORT).show()
Log.d("Error:::",t?.message)
}
override fun onResponse(call: Call<List<Hero>>?, response: Response<List<Hero>>?) {
mHeroDataList.clear()
if (response != null && response.isSuccessful && response.body() != null) {
closeDialog(dialog)
mHeroDataList .addAll(response.body()!!)
setAdapter(mHeroDataList)
}
}
})
app > build.gradle
// Retrofit
implementation ("com.squareup.retrofit2:retrofit:$retrofit_version") {
// exclude Retrofit’s OkHttp peer-dependency module and define your own module import
exclude module: "okhttp"
}
// OkHttp and a logging interceptor
implementation("com.squareup.okhttp3:okhttp:$okhttp_version")
implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"
project > build.gradle
buildscript {
...
ext.retrofit_version = '2.6.0'
ext.okhttp_version = '4.0.0'
...
}
package.name > external > ApiClient.kt
object ApiClient {
private const val BASE_URL = "https://test.apiary-mock.com/"
private var retrofit: Retrofit? = null
val apiClient: Retrofit
get() {
if (retrofit == null) {
val logging = HttpLoggingInterceptor()
logging.apply {
level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
}
val client: OkHttpClient = OkHttpClient.Builder()
.addInterceptor(logging)
.build()
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return retrofit!!
}
}
Usage
val carRestService = ApiClient.apiClient.create(CarRestService::class.java)
Sources
exclude module
okhttp
okhttp-logging-interceptor