I am building an api client using retrofit with this method:
private fun createNewApiClient(authRefreshClient: AuthRefreshClient,
preferencesInteractor: PreferencesInteractor): ApiClient {
val loggingInterceptor = HttpLoggingInterceptor(PrettyLogger())
loggingInterceptor.level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
val okHttpClient = createHttpClientBuilder()
.addInterceptor(loggingInterceptor)
.build()
return Retrofit.Builder()
.client(okHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(Interactors.apiEndpoint)
.build()
.create(ApiClient::class.java)
}
Debug is set to true in my generated BuildConfig file:
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
}
I can confirm that the call I am making with this client is being made because I put a lot statement in the throwable portion of RX's subscribe:
Interactors.api.apiClient.getUserByEmail(email).
.subscribe({
Log.d("Email exists")
//Success
}, {
Log.e("Call is failing")
}
})
But the body of the request is not showing up in my log statements. Nothing from okhttp is showing up. What is wrong with my implemention of okhttp?
Try to replace your PrettyLogger() with logger from HttpLoggingInterceptor
So replace yours:
val loggingInterceptor = HttpLoggingInterceptor(PrettyLogger())
in to:
val loggingInterceptor = HttpLoggingInterceptor()
Related
I am using Koin as a DI for my app. I created a module:
object NetworkModule {
fun get() = module {
single {
val authenticationInterceptor = Interceptor { chain ->
// Request customization goes here
}
OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.addInterceptor(authenticationInterceptor) //Not all clients might have this interceptor
.build()
}
single {
Retrofit.Builder()
.baseUrl("example.com")
.client(get(/* I would like to send some paramter here */))
.addConverterFactory(GsonConverterFactory.create(get()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
.create(Api::class.java)
}
}
}
How can I create different HttpClient or Retrofit instances which have different parameters set or has different instantiation? For instance, in some cases, I might need OkHttpClient with AutheniticationInterceptor and in some other cases my client might not need to use it.
Can I pass some parameters when calling get() so that I can get different instances? Any suggestions would be apprieciated.
You can use named properties - e.g.
single<OkHttpClient>(named("auth")){
// here you pass the version with authinterceptor
}
single<OkHttpClient>(named("noAuth")){
// here you pass the version without authinterceptor
}
Then in your get() method you pass the name, e.g.
.client(get(named("auth")))
You can do like below (Use koin latest version for named property).Also why I use single and factory because
single— declare a singleton definition of given type. Koin keeps only one instance of this definition
factory — declare a factory definition of given type. Koin gives a new
instance each time
const val WITH_AUTH: String = "WITH_AUTH"
const val WITH_OUT_AUTH: String = "WITH_OUT_AUTH"
val remoteModule = module {
factory(named("HEADERS")) {
val map = it.get<MutableMap<String, String>>(0)
Interceptor { chain ->
val original = chain.request()
val request = original.newBuilder()
map.forEach { entry ->
request.addHeader(entry.key, entry.value)
}
chain.proceed(request.build())
}
}
factory(named("auth")) {
OkHttpClient.Builder().apply {
map["AUTHORIZATION"] = "token"
readTimeout(1, TimeUnit.MINUTES)
connectTimeout(2, TimeUnit.MINUTES)
writeTimeout(1, TimeUnit.MINUTES)
addInterceptor(get(named("HEADERS"), parameters = {
parametersOf(map)
}))
}.build()
}
factory(named("auth")) {
Retrofit.Builder()
.baseUrl("base_url")
.client(get(named("auth")))
//.addCallAdapterFactory()
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiService::class.java)
}
single(named("noAuth")) {
val map = mutableMapOf(ACCEPT to CONTENT_TYPE)
OkHttpClient.Builder().apply {
readTimeout(1, TimeUnit.MINUTES)
connectTimeout(2, TimeUnit.MINUTES)
writeTimeout(1, TimeUnit.MINUTES)
addInterceptor(get(named("HEADERS"), parameters = {
parametersOf(map)
}))
}.build()
}
single(named("noAuth")) {
Retrofit.Builder()
.baseUrl("base_url")
.client(get(named("noAuth")))
//.addCallAdapterFactory()
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiService::class.java)
}
}
Now in your activity or viewModel
protected val apiServiceWithoutHeader: ApiService by inject(named(WITH_OUT_HEADER))
protected val apiServiceWithHeader: ApiService by inject(named(WITH_HEADER))
with above object call appropriate API
I have a basic retrofit setup in kotlin.
val BASE_URL: String = "http://10.0.2.2:5000/"
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
private val interceptor: HttpLoggingInterceptor = HttpLoggingInterceptor().apply {
this.level = HttpLoggingInterceptor.Level.BODY
}
private val client: OkHttpClient = OkHttpClient.Builder().apply {
this.addInterceptor(interceptor)
}.build()
private val retrofit = Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.baseUrl(BASE_URL)
.client(client)
.build()
val service: Api by lazy {
retrofit.create(Api::class.java)
}
I want to check if the server I'm fetching my data from is running - if its not I want to fall back on the local DB for basic functionality. I tried something similar at first but there's a couple of things that are wrong with this approach. First of all the request timeout period is 10 seconds long, which is a little bit more than you'd want it to be for an app. Second, well, it doesn't really work, it'll still throw an exception if the server is offline.
fun serverReachable(): Boolean {
return try {
GlobalScope.async {
// call whatever api function here
}
true
} catch (e: Exception) {
false
}
}
Is there are quick and dirty version of checking if the server is up?
i have this factory which is used for all outgoing requests in the app, is it possible to add a header here (app version) instead of on all requests?
other examples ive seen all seem to use a different syntax for the factory, i think its an older one but i am not sure
object RetrofitFactory {
val makeRetrofitService: RetrofitService by lazy {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder()
.addInterceptor(interceptor)
.build()
Retrofit.Builder()
.baseUrl("${CustomURI.BaseWebsite}/")
.addConverterFactory(GsonConverterFactory.create(GsonBuilder().create()))
.client(client)
.build().create(RetrofitService::class.java)
}
}
You can add multiple interceptors to your OkHttpClient.
It should something like this:
This is your logging interceptor:
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
This is a header one
OkHttpClient.Builder().apply {
addInterceptor { chain ->
val request = chain.request()
val builder = request
.newBuilder()
.header("SOME", "SOME")
.method(request.method(), request.body())
val mutatedRequest = builder.build()
val response = chain.proceed(mutatedRequest)
response
}
addInterceptor(interceptor) // this is your http logging
}.build()
Change SOME and SOME with your preferred values.
I found this solution , you can add this by using Interceptor
in this link How to define a Header to all request using Retrofit?
RequestInterceptor requestInterceptor = new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
request.addHeader("User-Agent", "Retrofit-Sample-App");
}
};
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://api.github.com")
.setRequestInterceptor(requestInterceptor)
.build();
In my application i want get data from server and for this i should add some header such as Accept and Content_Type .
For connect to server i used Retrofit library.
For set headers i use okHttp client and i write below codes, but not set header to api response!
My Client codes:
class ApiClient() {
private val apiServices: ApiServices
init {
//Gson
val gson = GsonBuilder()
.setLenient()
.create()
//Http log
val loggingInterceptor = HttpLoggingInterceptor()
loggingInterceptor.level =
if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
//Http Builder
val clientBuilder = OkHttpClient.Builder()
clientBuilder.interceptors().add(loggingInterceptor)
clientBuilder.addInterceptor { chain ->
val request = chain.request()
request.newBuilder().addHeader(
CONTENT_TYPE,
APPLICATION_JSON
).build()
chain.proceed(request)
}
clientBuilder.addInterceptor { chain ->
val request = chain.request()
request.newBuilder().addHeader(
ACCEPT,
APPLICATION_JSON
).build()
chain.proceed(request)
}
//Http client
val client = clientBuilder
.readTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
.connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
.callTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build()
//Retrofit
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL + BASE_URP_PREFIX)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.addConverterFactory(ScalarsConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
.build()
//Init mapApiServices
apiServices = retrofit.create(ApiServices::class.java)
}
companion object {
private var apiClient: ApiClient? = null
fun getInstance(): ApiClient =
apiClient ?: synchronized(this) {
apiClient
?: ApiClient().also {
apiClient = it
}
}
}
}
How can i fix it?
The first option to add a static header is to define the header and respective value for your API method as an annotation. The header gets automatically added by Retrofit for every request using this method. The annotation can be either key-value-pair as one string or as a list of strings.
The example above shows the key-value-definition for the static header:
Further, you can pass multiple key-value-strings as a list encapsulated in curly brackets {} to the #Headers annotation.
How you can pass multiple key-value-strings as a list encapsulated in curly brackets:
A more customizable approach are dynamic headers. A dynamic header is passed like a parameter to the method. The provided parameter value gets mapped by Retrofit before executing the request.
Define dynamic headers where you might pass different values for each request:
Happy Coding!! 😎
I'm using retrofit to get some data from the Flickr api. The method I'm making the call in looks like this:
public static List<String> getImageIds(int size) {
Call<PhotosList> call = flickrService.getPhotos(apiKey, format, "1");
Log.d("TEMP_TAG", "photo url: " + call.request().url().toString());
photoIds = new ArrayList<String>();
call.enqueue(new Callback<PhotosList>(){
#Override
public void onResponse(Call<PhotosList> call, Response<PhotosList> response) {
Log.d("TEMP_TAG", "it's getting here");
PhotosList photosList = response.body();
List<Photo> photos = photosList.getPhotos().getPhoto();
for(Photo photo : photos) {
Log.d("TEMP_TAG", "adding photo id to list: " + photo.getId());
photoIds.add(photo.getId());
}
}
#Override
public void onFailure(Call<PhotosList> call, Throwable t) {
// TODO: Clean up
Log.d("TEMP_TAG", "photoId: ");
}
});
Log.d("TEMP_TAG", "it's getting here too");
return photoIds;
}
However it is never getting into the onResponse() method. The first log statement within onResponse() never prints, neither does the log statement in onFailure(). When I try entering the URL that is returned by call.request().url().toString() in the browser it works fine, and I get the expected JSON. Why is my enqueue() method never firing?
Thanks for any help!
Use HttpLoggingInterceptor along with Retrofit.
If this helps, add this inside your build.gradle -
//Retrofit and OkHttp for Networking
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
//Logging Network Calls
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
Inside your APIClient class add this -
public class ApiClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(){
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();
if(retrofit==null){
retrofit = new Retrofit.Builder()
.baseUrl(BuildConfig.baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
}
return retrofit;
}
}
Kotlin Code
val interceptor : HttpLoggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
val client : OkHttpClient = OkHttpClient.Builder().apply {
addInterceptor(interceptor)
}.build()
fun getService(): Service {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(LiveDataCallAdapterFactory())
.client(client)
.build()
.create(Service::class.java)
}
And you will be able to log the Retrofit Network calls that you make.
Let me know if you need more information.
An OkHttp interceptor which logs HTTP request and response data.
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(Level.BASIC);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(logging)
.build();
You can change the log level at any time by calling setLevel.
There are 4 levels: NONE, BASIC, HEADERS, BODY
To log to a custom location, pass a Logger instance to the constructor.
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new
Logger() {
#Override public void log(String message) {
Log.d(TAG, "message: ");
}
});
From Gradle
compile 'com.squareup.okhttp3:logging-interceptor:(insert latest version)'
Follow this reference
EDITED: I also found this library which has a very nice structure and clean log. Try it!!
You can use the following class to log API calls
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
object HTTPLogger {
fun getLogger(): OkHttpClient {
/*
* OKHTTP interceptor to log all API calls
*/
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder()
.addInterceptor(interceptor)
.build()
return client
}
}
You can then call this class in your retrofit instance class like this
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
object RetrofitClientInstance {
private var retrofit: Retrofit? = null
val retrofitInstance: Retrofit?
get() {
if (retrofit == null) {
retrofit = Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(HTTPLogger.getLogger())
.build()
}
return retrofit
}
}
The dependency required is
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'