Android Retrofit 2.0.0-beta2 Post string body dynamic headers - android

Retrofit 2.0.0-beta2
#Headers({
"Authorization: {authorization}",
"Content-Type: application/json"
})
#POST("/api/{id}/action/")
Call<String> postfn(#Header("Authorization") String authorization, #Path("id") String id, #Body String body);
i am using Gson converter
.addConverterFactory(GsonConverterFactory.create(gson))
i am getting error code=400, message=Bad Request Should i use a custom
converter?
Please help

You can't put this two things together.
There are two ways to put dynamic headers on requests with retrofit 2.0
1: put it only in method signature
#Headers({
"Content-Type: application/json"
})
#POST("/api/{id}/action/")
Call<String> postfn(#Header("Authorization") String authorization, #Path("id") String id, #Body String body);
2: using request interceptor to add fixed dynamic headers
public class TraktvApiProvider implements Provider<TraktvApi> {
public static final String BASE_URL = "https://api-v2launch.trakt.tv/";
#Override
public TraktvApi get() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(JacksonConverterFactory.create())
.build();
retrofit.client().interceptors().add(new LoggingInterceptor());
return retrofit.create(TraktvApi.class);
}
private class LoggingInterceptor implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
request = request.newBuilder()
.addHeader("trakt-api-version", "2")
.addHeader("trakt-api-key", "[YOUR-API-KEY]")
.build();
Response response = chain.proceed(request);
String bodyString = response.body().string();
Log.d("Retrofit", "---------------------------------- REQUEST ----------------------------------");
Log.d("Retrofit", String.format("%s - %s", request.method(), request.url()));
Log.d("Retrofit", request.headers().toString());
Log.d("Retrofit", "---------------------------------- REQUEST ----------------------------------");
Log.d("Retrofit", "---------------------------------- RESPONSE ----------------------------------");
Log.d("Retrofit", response.headers().toString());
Log.d("Retrofit", "Body: " + bodyString);
Log.d("Retrofit", "---------------------------------- RESPONSE ----------------------------------");
return response.newBuilder()
.body(ResponseBody.create(response.body().contentType(), bodyString))
.build();
}
}
}

I moved back to the stable version 1.9 and intercepting worked fine.

Related

How to solve response code 403 from AWS in an Android project?

I am using retrofit to make a POST call to AWS server. It gives me the following error
Response{protocol=h2, code=403, message=, url=https://9oe8xt95sj.execute-api.ap-southeast-1.amazonaws.com/voip-dev-wa/staging/Device/registerCustomer}
My Retrofit method is as below
Retrofit retrofit;
retrofit = new Retrofit.Builder()
.baseUrl(ApiService.API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
apiService = retrofit.create(ApiService.class);
ApiService.java
String API_BASE_URL = "SOME String";
#POST("registerCustomer")
#Headers({"Content-Type: application/json", "accept: application/json"})
Call<RegisterResponse> register(#Body Register register);
How to solve this?
The problem is I did not pass the access token as the header. So it is responding forbidden error.
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.addInterceptor(new Interceptor() {
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request.Builder ongoing = chain.request().newBuilder();
ongoing.addHeader("Content-Type", "application/json");
ongoing.addHeader("accept", "application/json");
ongoing.addHeader("Authorization", "Bearer " + AppSetting.getInstance().getSDKDataManager().getAccessToken());
return chain.proceed(ongoing.build());
}
});

Error 401 from retrofit even after setting the Authorization Token

Trying to access an api with #POST and I already set my #Header("Authorization") String TOKEN.
I've tried it with #GET and it worked, but I'm passing a some form fields so I need to use #POST
#POST("details")
#FormUrlEncoded
Call<Play> playTrack(
#Header("Authorization") String TOKEN,
#Field("event_id") int event_id,
#Field("longitude") double longitude,
#Field("latitude") double latitude
);
Try to create a header interceptor and add it to OkHttpClient :
Interceptor headerIntercepter = new Interceptor() {
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
return chain.proceed( chain.request().newBuilder().addHeader("authorization-
client", accessToken).build());
}
};
OkHttpClient client = new OkHttpClient.Builder().connectTimeout(120, TimeUnit.SECONDS).readTimeout(120, TimeUnit.SECONDS)
.addInterceptor(headerIntercepter)
.build();
try {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Server_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
apiService = retrofit.create(Api.class);
try using Multipart on annotation
#Multipart
#POST("details")
Call<ResponseBody> playTrack(
#Header("Authorization") String token,
#Part("event_id") RequestBody eventId,
#Part("longitude") RequestBody longitude,
#Part("latitude") RequestBody latitude,
);
make sure to pass a RequestBody as params
val latitude = RequestBody.create(MediaType.parse("text/plain"), doubleLatitude.toString())
Seeing a 401 response means that the request was successfully executed
and the server returned that status code. This is not a problem with
Retrofit, but in whatever authentication information you are including
in the request that the server expects.
Try with postman with the same data and check
N.B: Don't forgot to add Token Type as prefix to your token

Retrofit 2.x.x + Okhttp3 intercepter + Dagger +Rx - Connection not closed

I'm using
Retrofit 2.2.0 + okhttp3 Intercepter + GSONConverterFactory (Dagger2)+ RxJava2.
When checking on the server, it seem like the connection made by the app is kept alive, and not closed even after response is received.
So basically I have
App module - Where Retrofit with GSONCOnverterFactory and okhttp client and it's interceptor is present.
App Module class :
#Singleton
#Provides
protected MyService providesMyService(#Named("MyService") Retrofit retrofit) {
return retrofit.create(MyService.class);
}
#Singleton
#Provides
#Named("MyService")
protected Retrofit providesMyRetrofit(GsonConverterFactory factory) {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(3000, TimeUnit.MILLISECONDS);
builder.readTimeout(3000, TimeUnit.MILLISECONDS);
builder.addInterceptor(new MyInterceptor());
builder.addNetworkInterceptor(new CachingControlInterceptor());
//caching
builder.cache(MyCache.getCache());
builder.addInterceptor(new HttpLoggingInterceptor()
.setLevel(loggingLevel));
try {
return new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(builder.build())
.addConverterFactory(factory)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
} catch (Exception e) {
}
}
My Interceptor :
#Override
public Response intercept(Chain chain) throws IOException {
final Charset UTF8 = Charset.forName("UTF-8");
final String userPassword = USERNAME + ":" + PASSWORD;
Request original = chain.request();
Request request = original.newBuilder()
.header("User-Agent", SOME_AGENT)
.header("Authorization", "Basic " + new String(Base64.encodeBase64(userPassword.getBytes(UTF8)), UTF8))
.header("Content-Type", "application/json; charset=utf-8")
.header("Keep-Alive", "timeout = 3")
.method(original.method(), original.body())
.build();
Response response = chain.proceed(request);
return response;
}
this is Rx Code :
MyApp.getInstance().getAppComponent()
.getMyService()
.getData(queryMap, resultValues)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe((MyResponse myResponse) -> {
//success result handled here
}, throwable -> {
//exception result handled here
});
I don't see any warning in code or in logcat. Passing Keep-Alive : timeout in header is not helping too.
How can I verify from the app side if connection is closed properly, or if it is kept open even after the response is received on the app ?

How to Add GSON CallAdapterFactory only when Retrofit Response is Succesfull

I have a REST Server, My problem is whenever my response is not successful i want to parse the error from response body and show it to the user (pass the error info to the calling Activity)
#Named("rest_api")
#Singleton
#Provides
Interceptor provideRESTInterceptor(final UserManager userManager) {
return new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
String token = userManager.getJwt();
Request request = original.newBuilder()
.header("Accept", "application/json")
.header("Authorization", "Bearer "+token)
.method(original.method(), original.body())
.build();
Log.i(LOG_TAG, "REQUEST URL "+request.uri());
Response response = chain.proceed(request);
if(!response.isSuccessful()) {
// How do i send this error to my Activity.
APIError apiError = new APIError(response.code(),response.body().string());
}
// Customize or return the response
return response;
}
};
}
I am using RxJavaConverter
#Named("rest_api")
#Singleton
#Provides
Retrofit provideRESTRetrofit(#Named("rest_api")OkHttpClient client, Converter.Factory converter, CallAdapter.Factory rxJava) {
return new Retrofit.Builder()
.baseUrl(PUBLIC_PRODUCTION_URL)
.client(client)
.addCallAdapterFactory(rxJava)
.addConverterFactory(converter)
.build();
}
Since Retrofit 2.0, even if the response is not successful it tries to convert the data with given GSON into (POJO), and thus throw an error, and i lost the actual message of the error.
As #david:mihola suggested it worked, using Retrofit Response object i was able to achieve this.
Response<MyObject> response;
if(response.isSucessful) {
MyObject obj = response.body();
} else {
// You can process your error message from the reponse
}
It really saved me from lot manual GSON parsing

Android OAuth Retrofit Access Token Request

Can anyone tell the exact format to convert below code into retrofit
curl -X POST -d "grant_type=password&username=admin&password=admin&scope=read+write" -u"clientId:clientSecret" http://myserver/o/token/
I have tried something like this but it isn't working
#FormUrlEncoded
#POST("/o/token/")
AccessTokenResponse getToken(#Field("client_id") String client_id, #Field("client_secret") String client_secret,
#Field("grant_type") String grant_type, #Field("username") String username,
#Field("password") String password, #Field("scope") String scope);
Client credentials should be authenticated with Basic Authentication. i.e with header
Authorization: Basic base64encode(clientId:clientSecret)
where base64encode(clientId:clientSecret) is the actual base64 encoded string of clientId:clientSecret. So to update your interface it might look something more like
public interface OAuthTokenService {
#POST("/api/token")
#FormUrlEncoded
#Headers({
"Accept: application/json"
})
AccessTokenResponse getAccessToken(#Field("grant_type") String grantType,
#Field("username") String username,
#Field("password") String password,
#Header("Authorization") String authorization);
}
Then to set the header, do something like
public class Main {
public static void main(String[] args) {
RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint("http://localhost:8080")
.setConverter(new JacksonConverter())
.build();
OAuthTokenService service = restAdapter.create(OAuthTokenService.class);
byte[] credentials = "clientId:clientSecret".getBytes();
String basicAuth = "Basic " + Base64.getEncoder().encodeToString(credentials);
AccessTokenResponse response = service
.getAccessToken("password", "admin", "admin", basicAuth);
System.out.println(response.getAccessToken());
}
}
Note the above uses Java 8 for the java.util.Base64 class. You may not be using Java 8, in which case you will need to find a different encoder.
I am also using Jackson for conversion, only because I don't use Gson. The above has been tested and should work for you also.
With OkHttp interceptors this is made easier.
Interceptor interceptor = chain -> {
Request original = chain.request();
Request request = original.newBuilder()
.header("Authorization", Credentials.basic(CLIENT_ID, CLIENT_SECRET))
.method(original.method(), original.body())
.build();
return chain.proceed(request);
};
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();
return new Retrofit.Builder()
.baseUrl(baseURL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
The Credentials.basic method will base 64 encode your client id and client secret. The interceptor is then attached to the OkHttpClient client and added to the Retrofit object.

Categories

Resources