I use retrofit for async server requests.
Below is declaration of API client:
object NasaApiClient {
private const val NASA_BASE_URL="https://images-api.nasa.gov/"
fun getClient(): NasaApiService {
val logging = HttpLoggingInterceptor()
logging.level = HttpLoggingInterceptor.Level.BODY
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(logging)
.readTimeout(20, TimeUnit.SECONDS)
.build()
val gson = GsonBuilder().create()
val retrofit = Retrofit.Builder()
.baseUrl(NASA_BASE_URL)
.client(okHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
return retrofit.create(NasaApiService::class.java)
}
}
Also i use Rx method for this GET request:
interface NasaApiService {
#GET("search")
fun mediaInfo(#Query("nasa_id")nasa_id:String): Single<MediaDetail>
}
fun fetchMediaDetails(nasaId:String){
_networkState.postValue(NetworkState.LOADING)
try {
compositeDisposable.add(
apiService.mediaInfo(nasaId)
.observeOn(Schedulers.io())
.subscribeOn(Schedulers.io())
.subscribe ({
Log.e("MediaDetail",it.toString())
_downloadedMediaDetailsResponse.postValue(it)
_networkState.postValue(NetworkState.LOADED)
},{
_networkState.postValue(NetworkState.ERROR)
Log.e("MovieDetailsDataSource", it.message.toString())
})
)
}
catch (e: Exception){
Log.e("MediaDetailsDataSource", e.message.toString())
}
}
Retrofit doesn't show server HTTP response in log. Why does it happen?
Logging interceptor enabled!
After updating version of retrofit and okHttp it works!
//Retrofit
def retrofit_version = "2.9.0"
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit_version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0'
Related
I have weather api to parse data for 10 days
All it's good , but I have problem with retrofit now , I have app crashes , my URL(with API) have / in the end.
But still don't working.
Also I have dependency injection for retrofit.
Goal is to get data from api.
Hope , that you will help me to resolve this problem.
package const
const val BASE_URL = "https://api.weatherapi.com/v1/forecast" +
".json?key=a9f9d57b6e064f16b28141346231001&q=London&days=10&aqi=no&alerts=no/" // error here
const val apikey = "a9f9d57b6e064f16b28141346231001"
const val WeatherDays = 10
interface WeatherServiceAPI {
#GET("forecast.json")
suspend fun Weatherday(
#Query("days") days : Int
) : WeatherResponse
#GET("forecast.json")
suspend fun searchcitybycoord(#Query("lat")lat:String) : List<WeatherLocationDTO>
#GET("forecast.json")
suspend fun searchingbyCity(#Query("q") name: String) : List<WeatherLocationDTO>
companion object{
operator fun invoke(
connectivityInterceptor: Interceptor
):WeatherServiceAPI{
val requestInterceptor = Interceptor{
chain -> val url = chain.request()
.url
.newBuilder()
.addQueryParameter("key", apikey)
.build()
val request = chain.request()
.newBuilder()
.url(url)
.build()
return#Interceptor chain.proceed(request)
}
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(requestInterceptor)
.addInterceptor(connectivityInterceptor)
.build()
return Retrofit.Builder()
.client(okHttpClient)
.baseUrl("https://api.weatherapi.com/v1/") // error line
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(WeatherServiceAPI::class.java)
}
}
}
#Provides
#Singleton
fun providerepository(api:WeatherServiceAPI):ForecastRepository{
return ForecastRepositoryImpl(api)
}
#Provides
#Singleton
fun provideWeatherApiService(retrofit: Retrofit) =
retrofit.create(WeatherServiceAPI::class.java)
#Provides
#Singleton
fun provideRetrofit ( okHttpClient: OkHttpClient) = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.client(okHttpClient)
.build()
#Provides
#Singleton
fun provideOkhttpClient(interceptor: Interceptor): OkHttpClient {
val httpBuilder = OkHttpClient.Builder().addInterceptor(interceptor)
return httpBuilder.build()
}
#Provides
#Singleton
fun provideinterceptor():Interceptor{
return Interceptor {
val request =it.request().newBuilder()
val actualRequest = request.build()
it.proceed(actualRequest)
}
}
Given what else you have in the code, your base URL should be https://api.weatherapi.com/v1/.
forecast.json comes from the #GET annotations, and the query parameters will need to come from #Query-annotated parameters to your Retrofit interface functions.
class RetrofitInstance {
companion object {
private val retrofit by lazy {
val logging = HttpLoggingInterceptor()
logging.setLevel(HttpLoggingInterceptor.Level.BODY)
val client = OkHttpClient.Builder()
.addInterceptor(logging)
.build()
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
}
val api by lazy {
retrofit.create(RickAndMortyServiceApi::class.java)
}
} }
Error message
"Type 'Lazy<TypeVariable(T)>' has no method 'getValue(RetrofitInstance.Companion, KProperty<*>)' and thus it cannot serve as a delegate"
Kotlin version 1.6
I have tried this code snippet on my machine, and it works fine:
companion object {
private val retrofit by lazy {
val logging = HttpLoggingInterceptor()
logging.setLevel(HttpLoggingInterceptor.Level.BODY)
val client = OkHttpClient.Builder()
.addInterceptor(logging)
.build()
Retrofit.Builder()
.baseUrl("https://www.google.com")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
}
val api by lazy {
retrofit.create(DummyClass::class.java)
}
}
So i suggest you double-check your code for typos, or you can check for dependency versions. Versions that i'm using are:
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation("com.squareup.okhttp3:logging-interceptor:4.9.3")
I am using retrofit to communicate with the BE and I want to the log the URL i am hitting and the body I am sending and the response I am getting (like 401, 404).
This is to know if I am hitting the right url what is the header, body and the actual URL to verify I am sending all the right info required
I implemented HttpLoggingInterceptor but that does not log it, or I am logging it the right way
can you suggest please.
object RetrofitBuilder {
private const val BASE_URL = "https://xxxx.xxxxxx.com/"
private fun getRetrofit(): Retrofit {
var interceptor: HttpLoggingInterceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder().addInterceptor(interceptor).build()
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build() //Doesn't require the adapter
}
val apiService: ApiService = getRetrofit().create(ApiService::class.java)
}
AppService
#POST
suspend fun postData(#Url url: String, #Body Data: Data, #Header("Autzn") authHeader: String)
ApiHelper
//NOTE: here i am using the different URL as but not the baseUrl defined on the top
apiService.postData("https://abcd.com/msg/oauth2/123456", Data,
"token")
//Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.2.1'
Please suggest how to log the url info
thanks
R
just give HttpLoggingInterceptor.Logger interface.
logging interceptor should be like this.
val loggingInterceptor = HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
override fun log(message: String) {
Timber.tag("retrofit").d(message)
}
})
This is How I'm logging url in logs
val retrofitApi: RetrofitInterface
get() {
if (retrofitInterface == null) {
val logger = HttpLoggingInterceptor()
logger.level = HttpLoggingInterceptor.Level.BODY
val okHttpClient = OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.addInterceptor(logger).build()
val retrofit = Retrofit.Builder()
.baseUrl(REST_HOST)
.addConverterFactory(GsonConverterFactory.create(GsonBuilder()
.setLenient()
.create()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
.build()
retrofitInterface = retrofit.create(RetrofitInterface::class.java)
}
return this.retrofitInterface!!
}
I suggest you to use HttpLoggingInterceptor with log level, logging can be heavy task especially with images(printing raw bytes), and with big images(40mb+) can throw OOM exception.
So use logging for debug purpose.
public HttpLoggingInterceptor loggingInterceptor() {
HttpLoggingInterceptor loggingInterceptor
= new HttpLoggingInterceptor(message -> Log.d(TAG, message));
loggingInterceptor.setLevel(BuildConfig.DEBUG ? HttpLoggingInterceptor.Level.BODY : HttpLoggingInterceptor.Level.NONE);
return loggingInterceptor;
}
I'm trying to logout user in case of a 401 response from any API call in the project.
I'm using Koin Module. Here's the code snippet of Koin Module:
single {
retrofit(get())
}
single {
client()
}
private fun retrofit(okHttpClient: OkHttpClient): Retrofit {
val gson = GsonBuilder()
.setLenient()
.create()
return Retrofit.Builder()
.baseUrl(Config.BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
.build()
}
private fun client(): OkHttpClient {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
return OkHttpClient.Builder()
.connectTimeout(1, TimeUnit.MINUTES)
.writeTimeout(1, TimeUnit.MINUTES)
.readTimeout(1, TimeUnit.MINUTES)
.addInterceptor(object : Interceptor {
#Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val request: Request = chain.request()
val response: Response = chain.proceed(request)
// todo deal with the issues the way you need to
if (response.code == 200) {
//Open LogIn Activity
}
return response
}
}).build()
}
How can I call activity from within the interceptor? Or is there any other preferred way to do this?
Any help is appreciated.
I have used retrofit2 library in android. I am getting 401 Unauthorized error. if anyone have solved this issue so please tell me here. I learn retrofit2 use in android.
this is APIClient class.
APIClient class :
public class APIClient {
private static Retrofit retrofit = null;
private static OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(7, TimeUnit.MINUTES)
.readTimeout(7, TimeUnit.MINUTES)
.writeTimeout(7, TimeUnit.MINUTES)
.build();
public static Retrofit getClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
retrofit = new Retrofit.Builder().baseUrl("http://www.example.com/").addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient).build();
return retrofit;
}
}
this is my interface.
public interface APIInterface {
#GET("/teacher/api/getStudentTakeAttendanceList")
Call<List<Apiresponse>> getstudentAttendanceListView(#Query("teacherId") int userId);
// Callback<List<Apiresponse>> studentAttendanceListView(#Query("teacherId") int userId);
}
this is my final call.
final Call<List<Apiresponse>> getstudentAttendanceListView = apiInterface.getstudentAttendanceListView(userId);
getstudentAttendanceListView.enqueue(new Callback<List<Apiresponse>>() {
#Override
public void onResponse(Call<List<Apiresponse>> call, Response<List<Apiresponse>> response) {
Log.d("responsecode:::", "" + response.code());
if (progressDialog.isShowing()) {
progressDialog.dismiss();
}
Log.e("response::", "" + response.errorBody());
// Log.e("response::", "" + response.body());
}
#Override
public void onFailure(Call<List<Apiresponse>> call, Throwable t) {
call.cancel();
if (progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
});
in app.gradle file.
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
output.
responsecode:::: 401
response::: okhttp3.ResponseBody$1#537beb4c
A 401 Unauthorized error means that you don't have the rights to access.
In your case it means that you have to add a header with a accessToken.
Here is explained how to do this.
you should add your api access token in the request header, you should ask your api developer for the headers keys,you should also try the request first with postman
Issue can be in yours Headers. "Authorization: Basic TUM6TUMxIU1D" solved my problem.
#Headers("Authorization: Basic TUM6TUMxIU1D")
#GET("nomenclature")
fun getNomenclature(#Query("access_token") accessToken: String): Single<Response>
401 Unauthorized Retrofit
It means you don't have the rights to access.
private fun getTestData() {
val client = OkHttpClient.Builder()
.addInterceptor(BasicAuthInterceptor("username","paswword"))
.build()
val gson = GsonBuilder()
.setLenient()
.create();
val api = Retrofit.Builder()
.baseUrl(Baseurl)
//use this
.client(client)
//to solve the problem
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(ApiInterface::class.java)
api.getData().enqueue(object : Callback<Mytest?> {
override fun onResponse(call: Call<Mytest?>?, response: Response<Mytest?>?) {
//TODO("Not yet implemented")
val responseBody= response?.body()
val stringBuilder=StringBuilder()
stringBuilder.append(responseBody?.id)
Log.v("testjee",responseBody.toString())
}
override fun onFailure(call: Call<Mytest?>?, t: Throwable?) {
//TODO("Not yet implemented")
showInfo.toastShort("error"+ t?.message.toString())
Log.d("error",t.toString())
if (t != null) {
print("testjee"+t.message.toString())
}
}
})
}
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Headers
interface ApiInterface {
#GET("xxx/xxx")
fun getData(): Call<Mytest>
}
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.0'
//implementation 'com.squareup.retrofit2:converter-scalars:2.3.0'
implementation 'com.squareup.okhttp3:okhttp-ws:3.4.1'
implementation "com.squareup.okhttp3:okhttp-urlconnection:3.4.1"
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
implementation 'com.squareup.retrofit2:converter-jackson:2.1.0'
implementation 'com.squareup.retrofit2:converter-gson:2.2.0'
configurations.all {
// OkHttp 3.5.0+ includes the websockets API, so we need this to prevent a conflict
//exclude module: 'okhttp-ws'
resolutionStrategy.force 'com.squareup.okhttp3:okhttp:3.4.1'
}
import okhttp3.Credentials
import okhttp3.Interceptor
class BasicAuthInterceptor(username: String, password: String): Interceptor {
private var credentials: String = Credentials.basic(username, password)
override fun intercept(chain: Interceptor.Chain): okhttp3.Response {
var request = chain.request()
request = request.newBuilder().header("Authorization", credentials).build()
return chain.proceed(request)
}
}