Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Change API Base Url at Runtime(Retrofit,Android,Java)?

I need to change base url at run time. I have login button and when login button click time i am called my login api like below :

login api = http://192.168.0.61/api/authenticate

API_BASE_URL = http://192.168.0.61/api/

when i get success response from first api i get client server url for changing baseUrl.

CompanyUrlConfigEntity companyUrlConfigEntity = response.body(); like below :

String clientUrl = companyUrlConfigEntity. getBaseUrl();

                            clientUrl = http://192.168.0.238/api/

In this project mainly for client or company based.So they have their own server. Each company has using more than 20 api's. So i need to change base url .

I am also checked below link for changing base url:

https://futurestud.io/tutorials/retrofit-2-how-to-change-api-base-url-at-runtime-2

and changed code like that

public static void changeApiBaseUrl(String newApiBaseUrl) {
    API_BASE_URL = newApiBaseUrl;

    builder = new Retrofit.Builder()
            .baseUrl(API_BASE_URL)
                    .addConverterFactory(new NullOnEmptyConverterFactory())
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create(new Gson()));
}

when i debugged and checked my baseUrl then it shows properly like below:

API_BASE_URL =  http://192.168.0.238/api/



But when i call my customer api it shows the my first base url calling,
the url not changed.

expected customer api : http://192.168.0.238/api/customers
reality customer api : http://192.168.0.61/api/customers


I am also checked below link :

https://futurestud.io/tutorials/retrofit-2-how-to-use-dynamic-urls-for-requests

thats working , But each api need to pass fullPath url with each api like below:
@GET
public Call<ResponseBody> profilePicture(@Url String url);

But using this method , each api calling place i need to attach full path of url.

There is any other options? Please help me.

ServiceGenerator.class

    public class ServiceGenerator {

  public static String API_BASE_URL = "http://192.168.0.61/api/";

   private static Retrofit retrofit;

 private static OkHttpClient.Builder httpClient = new 
 OkHttpClient.Builder();

private static Retrofit.Builder builder =
        new Retrofit.Builder()
                .baseUrl(API_BASE_URL)
                .addConverterFactory(new NullOnEmptyConverterFactory())
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create(new 
       Gson()));

   private ServiceGenerator() {

   }

 public static void changeApiBaseUrl(String newApiBaseUrl) {
         API_BASE_URL = newApiBaseUrl;

       builder = new Retrofit.Builder()
            .baseUrl(API_BASE_URL)
                    .addConverterFactory(new NullOnEmptyConverterFactory())
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create(new Gson()));


}   

 public static Retrofit retrofit() {
    return retrofit;
}
public static <S> S createService(Class<S> serviceClass) {
    return createService(serviceClass, null, null);
}

  public static <S> S createService(Class<S> serviceClass,
                                  final String authToken,
                                  final ProgressListener progressListener) {
    if (authToken != null) {
           httpClient.addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request original = chain.request();

                final String headerValue = AUTHORIZATION_TYPE + authToken;
                Request request = original.newBuilder()
                        .header(AUTHORIZATION_HEADER_KEY, headerValue)
                        .method(original.method(), original.body())
                        .build();
                return chain.proceed(request);
            }
        });
    }

    addResponseProgressListener(progressListener);

    if (BuildConfig.DEBUG) {
        HttpLoggingInterceptor httpLoggingInterceptor = new 
        HttpLoggingInterceptor();
        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        httpClient.addInterceptor(httpLoggingInterceptor);
    }


    if (authToken != null) {
        if (picasso == null) {
            setUpPicasso(authToken);
        }
    }


    OkHttpClient client = httpClient.build();
    httpClient.connectTimeout(15, TimeUnit.SECONDS);
    httpClient.readTimeout(2, TimeUnit.MINUTES);
    httpClient.writeTimeout(2, TimeUnit.MINUTES);
    retrofit = builder.client(client).build();

    return retrofit.create(serviceClass);
}
}

LoginFragment.java

@OnClick(R.id.bt_login)
void onLogin() {

    checkValidityOfUser();

}

private void checkValidityOfUser() {
    final Login login = getLoginCredentials();

    Call<CompanyUrlConfigEntity> callCheckValidity = dataProcessController.
            getApiClient().
            checkValidityOfUsers(login.getUsername());

    callCheckValidity.enqueue(new Callback<CompanyUrlConfigEntity>() {
        @Override
        public void onResponse(Call<CompanyUrlConfigEntity> call,
                               Response<CompanyUrlConfigEntity> response) {


            if (response.code() == 200) {

                CompanyUrlConfigEntity companyUrlConfigEntity = response.body();

                boolean status = companyUrlConfigEntity.isValidUser();

                if (status) {

                    String baseUrls = companyUrlConfigEntity.
                            getBaseUrl();
                    baseUrls = baseUrls + "/api/";
                    ServiceGenerator.changeApiBaseUrl(baseUrls);
                    logins();
                } else {

                    ToastHelper.show("please contact  admin");

                }


            } else {

                ToastHelper.show("" + response.code() + response.message());

            }

        }

        @Override
        public void onFailure(Call<CompanyUrlConfigEntity> call, Throwable t) {

            ToastHelper.show("please contact  admin");
        }
    });
}


private void logins() {
    login = getLoginCredentials();
    Call<Void> callLogin = dataProcessController.
            getApiClient().
            login(login);

    callLogin.enqueue(new Callback<Void>() {
        @Override
        public void onResponse(Call<Void> call, Response<Void> response) {

            if (response.code() == 200) {

            } else if (response.code() == 401) {

            }
        }

        @Override
        public void onFailure(Call<Void> call, Throwable t) {

        }
    });
}
like image 474
jesto paul Avatar asked Nov 17 '22 22:11

jesto paul


1 Answers

Base on your comments, I would say that you are correctly changing the API url on your builder, but that your second call still uses an instance of service where the url has not changed.

To explain a little more, from what I understand this is how everything gets executed:

  • when fragment is created, the apiClient is created and pointing to the first url
  • with dataProcessController.getApiClient() in your first call, you are getting the service that is pointing to the first url and then execute the call.
  • when the call is successful, you read the new url from result and update the ServiceGenerator with that new url. Then you execute the logins() method.
  • and in that method, you recall the dataProcessController.getApiClient() and do the second call with it. However, as you never redid apiClient = ServiceGenerator.createService(ApiClient.class);, the apiClient instance you are getting is still pointing to the first url, because it hasn't been notified that the url changed.

What I would try here, would be to change the method getApiClient() in your DataProcessController class to something like this:

public ApiClient getApiClient() {
    apiClient =  ServiceGenerator.createService(ApiClient.class);
    return apiClient;
}

and see if this is work better.

Or if you don't want to regenerate the service inside that function, you can also do something like this:

public class DataProcessController { 
    private ApiClient apiClient = null; 

    private DataProcessController() { 
        regenerateClient(); 
    }

    public ApiClient getApiClient() { return apiClient; }

    // add this to regenerate the client whenever url changes
    public void regenerateClient() {
        apiClient = ServiceGenerator.createService(ApiClient.class);
    }
}

then, everytime you do change the url, do this:

ServiceGenerator.changeApiBaseUrl(baseUrls);
dataProcessController.regenerateClient();

and you should get a client that points to the correct url everytime you do dataProcessController.getApiClient()

like image 93
Macmist Avatar answered Jan 11 '23 14:01

Macmist