I am using Postman to hit server GET call with url. and adding headers like below in headers sections in postman so when run in postman it works and send data in body but In android using Retrofit not working with 401 error.
X-APIClient: {"apiClientId":"testing-account-cli","apiToken":"$2y$10$C/quaRQUsrWa30hjQJuckOXbW9kIZ.W3G1TlLMYg6lr/XDUes7SM."}
X-Header-Request: {"deviceId":"ffffffff-daac-6513-4eca-0c41298e00df"}
And It works on Postman. But In Android with Retrofit, it's not working 401 error.
1)
#GET("user-list")
Call<User> getUsers(#HeaderMap Map<String, String> headers);
2)
public static Map<String,String> addCustomHeaders()
{
headers = new HashMap<>();
headers.put("X-APIClient",
"\"apiClientId\":\"testing-account-cli\",\"apiToken\":\"$2y$10$C/quaRQUsrWa30hjQJuckOXbW9kIZ.W3G1TlLMYg6lr/XDUes7SM.");
headers.put("X-Header-Request", "\"deviceId\":\"ffffffff-daac-6513-4eca-0c41298e00df")
;
return headers;
}
3) Calling GET using below fails always
Call<User> call = api.getUsers(RetrofitClient.addCustomHeaders());
call.enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
Log.i(TAG, "GET User Success." + response.body().toString());
}
#Override
public void onFailure(Call<User> call, Throwable t) {
Log.i(TAG, "GET Failed Users." + t.getMessage());
}
});
Please Help whats wrong. As its always throwing 401 with authentication false and authorization false.
Try function below, I separated headers.
public static Map<String,String> addCustomHeaders()
{
HashMap<String, String> headers = new HashMap<>();
headers.put("apiClientId" ,"testing-account-cli");
headers.put("apiToken", "$2y$10$C/quaRQUsrWa30hjQJuckOXbW9kIZ.W3G1TlLMYg6lr/XDUes7SM.");
headers.put("deviceId","ffffffff-daac-6513-4eca-0c41298e00df");
return headers;
}
Use interceptor for header
public class HeaderInterceptor implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
request = request.newBuilder()
.header("apiClientId", "testing-account-cli")
.header("apiToken","$2y$10$C/quaRQUsrWa30hjQJuckOXbW9kIZ.W3G1TlLMYg6lr/XDUes7SM.")
.header("deviceId","ffffffff-daac-6513-4eca-0c41298e00df")
.build()
Response response = chain.proceed(request);
return response;
}
//add this class into retrofit class like
.addInterceptor(httpLoggingInterceptor)
.addInterceptor(new HeaderInterceptor())
Related
I am using Retrofit with the OkHttp Client and Jackson for Json Serialization and want to get the header of the response.
I know that i can extend the OkClient
and intercept it. But this comes before the deserialization process starts.
What i basically needs is to get the header alongside with the deserialized Json Object.
With Retrofit 1.9.0, if you use the Callback asynchronous version of the interface,
#GET("/user")
void getUser(Callback<User> callback)
Then your callback will receive a Response object
Callback<User> user = new Callback<User>() {
#Override
public void success(User user, Response response) {
}
#Override
public void failure(RetrofitError error) {
}
}
Which has a method called getHeaders()
Callback<User> user = new Callback<User>() {
#Override
public void success(User user, Response response) {
List<Header> headerList = response.getHeaders();
for(Header header : headerList) {
Log.d(TAG, header.getName() + " " + header.getValue());
}
}
For Retrofit 2.0's interface, you can do this with Call<T>.
For Retrofit 2.0's Rx support, you can do this with Observable<Result<T>>
In Retrofit 2.0.0, you can get header like this:
public interface Api {
#GET("user")
Call<User> getUser();
}
Call<User> call = api.getUser();
call.enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
// get headers
Headers headers = response.headers();
// get header value
String cookie = response.headers().get("Set-Cookie");
// TODO
}
#Override
public void onFailure(Call<User> call, Throwable t) {
// TODO
}
});
Much like you I wanted the headers along side of the payload. I needed access to the Etag. It takes some retro-foo, but you can do it. here's what I did. It's a dirty sample so dont take this as a best practices sample.
public static RestAdapter.Builder getRestBuilder(Context context) {
GsonBuilder gsonBuilder = GsonBuilderUtils.getBuilder();
Gson gson = gsonBuilder.create();
// **
// 1. create our own custom deserializer here
// **
final MyGsonConverter gsonConverter = new MyGsonConverter(gson);
OkHttpClient httpClient = MyPersonalOkHttpFactory.getInstance().getAuthHttpClient(context);
httpClient.networkInterceptors().add(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
Response response = chain.proceed(originalRequest);
// **
// 2. add the headers from the Interceptor to our deserializer instance
// **
gsonConverter.headers = response.headers();
return response;
}
});
RestAdapter.Builder builder = new RestAdapter.Builder()
.setClient(new OkClient(httpClient))
.setEndpoint(Common.getApiOriginUrl())
.setConverter(gsonConverter);
return builder;
}
private static class MyGsonConverter extends GsonConverter {
private Headers headers;
public MyGsonConverter(Gson gson) {
super(gson);
}
#Override
public Object fromBody(TypedInput body, Type type) throws ConversionException {
Object obj = super.fromBody(body, type);
// **
// 3. at this point, gson is called and you have access to headers
// do whatever you want here. I just set it on the return object.
// **
if (obj instanceof HeadersArrayList) {
((HeadersArrayList)obj).setHeaders(headers);
}
return obj;
}
}
public class HeadersArrayList<K> extends ArrayList<K>{
private Headers headers;
public Headers getHeaders() {
return headers;
}
public void setHeaders(Headers headers) {
this.headers = headers;
}
}
// the retrofit api for reference
#GET("/api/of/my/backend/{stuff}")
HeadersArrayList<String> getSomething(#Path("stuff") String stuff);
First print the entire response, body, code, message, header(by logging or something else) and try to find a clue from there.
I would recommend you to read the API docs and see the type of request it is asking for.
Use Postman to check which one of the following is working:
1.form-data
2.x-www-form-Urlencoded
3.raw
4.binary
And then accordingly set the annotations in the method declarations in the interface.
eg: in my case, it was taking x-www-form-Urlencoded so I had to mention it using
#FormUrlEncoded
#Headers("Content-Type: application/x-www-form-urlencoded")
in the method declaration.
Then used #Field annotations for individual value I was sending
like
Call<'ReturnObj'> Signup(#Field("name") String name, #Field("phoneNumber") long phoneNumber, #Field("password") String password, #Field("counter") int counter);
I am plugging Retrofit into my android app.
Here is how I build retrofit, notice the interceptor for the logging and headers.
public void buildRetrofit(String token){
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient.addNetworkInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.header("api-version", "1")
.method(chain.request().method(), chain.request().body())
.build();
return chain.proceed(newRequest);
}
});
httpClient.addInterceptor(logging);
Retrofit.Builder buidler = new Retrofit.Builder()
.baseUrl("XXX_HIDDEN_FORSTACKOVERFLOW")
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build());
retroFit = buidler.build();
}
I make the call like so
OrderApi orderApi = mainActivity.retroFit.create(OrderApi.class);
Call<Order> call = orderApi.getOpenOrder();
call.enqueue(new Callback<Order>() {
#Override
public void onResponse(Call<Order> call, Response<Order> response) {
Order a = response.body();
int b = 1;
}
#Override
public void onFailure(Call<Order> call, Throwable t) {
}
});
And here is how the actual request tag
public interface OrderApi {
#POST("/HIDDEN")
Call<Order> getOpenOrder();
}
Lastly, here is the order class
public class Order {
private String orderId;
private OrderStatus orderStatus;
public String getOrderId(){
return orderId;
}
public OrderStatus getOrderStatus() {
return orderStatus;
}
}
I get a response of 400. I have no idea why, and It works in postman etc. Something to note is that the response contains a lot more properties than just the ones in the class. I just want a proof on concept, but that shouldn't break things right?
.................
Managed to fix it. Had to send an empty body request as it was a post but I wasn't posting anything. API is dumb.
See here to send empty request Send empty body in POST request in Retrofit
I am using retrofit2 to logout in App but everytime it gives error406
: Not Acceptable : User is not logged in. . i am using retrofit custom
header authentication . Here is my Code :
logout code
public void logout()
{
Log.v("checkTokenbefore",Constants.token);
OkHttpClient httpClient1 = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Log.v("checkLogin",Constants.token+Constants.username+Constants.password) ;
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.addHeader("Accept-Language","application/json").addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("API_KEY", "a5XSE8XCdsY6hAoCNojYBQ")
.addHeader("X-CSRF-Token",Constants.token)
;
Request request = requestBuilder.method(original.method(),original.body()).build();
return chain.proceed(request);
}
}).build();
Retrofit retrofit1 = new Retrofit.Builder()
.baseUrl(Constants.API_BASE_URL)
.client(httpClient1)
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiInterface restAPI1 = retrofit1.create(ApiInterface.class);
Call<Logout> callLogout = restAPI1.userLogout(Constants.token,Constants.username,Constants.password);
callLogout.enqueue(new Callback<Logout>() {
#Override
public void onResponse(Call<Logout> call, retrofit2.Response<Logout> response) {
Log.v("responseLogout",response.code()+"code"+response.errorBody().toString()+response.message()) ;
}
#Override
public void onFailure(Call<Logout> call, Throwable t) {
}
});
}
While Following is the code for login which works fine :
public void loginQuestin(){
//checkValidation ();
/*
ApiInterface apiService =
ApiClient.create(ApiInterface.class) ;*/
ApiInterface restAPI = retrofit.create(ApiInterface.class);
Call<UserAgain> call = restAPI.userLogin(mEmailAddress.getText().toString().trim(),
mPassword.getText().toString().trim());
call.enqueue(new Callback<UserAgain>() {
#Override
public void onResponse(Call<UserAgain> call, Response<UserAgain> response) {
Log.v("check",response.code()+"login"+response.body().getToken()) ;
//response.body().getU
Constants.username = mEmailAddress.getText().toString().trim() ;
Constants.password = mPassword.getText().toString().trim() ;
if (response.code()==200) {
Log.v("checkAgain",response.code()+"login") ;
Constants.token = response.body().getToken() ;
startActivity(new Intent(LoginActivity.this, NavigationDrawerActivity.class));
}
}
#Override
public void onFailure(Call<UserAgain> call, Throwable t) {
Log.v("check","failed");
t.printStackTrace();
}
});
}
//API/Http client for login api call
public class ApiClient {
public static OkHttpClient httpClient = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder() .addHeader("Accept-Language","application/json")
.addHeader("content-type", "application/x-www-form-urlencoded").addHeader("API_KEY", "a5XSE8XCdsY6hAoCNojYBQ")
;
Request request = requestBuilder.build();
return chain.proceed(request);
}
}).build();
public static Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.API_BASE_URL)
.client(httpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
public static ApiInterface restAPI = retrofit.create(ApiInterface.class);
}
API Interface class
#POST("token")
Call<Token> getToken();
#FormUrlEncoded
#POST("login")
Call<UserAgain> userLogin(#Field("username") String param1, #Field("password") String param2);
#FormUrlEncoded
#POST("logout")
Call<Logout> userLogout(#Field("username") String param1 , #Field("password") String param2);
Login APi works fine give a response code of 200 OK . The major issue is encountered when working with added dynamic customn header on logout api (client xsrf token )
Reference :
https://futurestud.io/tutorials/retrofit-add-custom-request-header
api formats :
User Authentication/Login
Purpose: - User Login Rest URL: - /api/v1/people/login
Method:-POST Headers: Accept-Language: application/json API_KEY:
a5XSE8XCdsY6hAoCNojYBQ Content-Type: application/x-www-form-urlencoded
X-CSRF-Token:
User Logout
Purpose: - User Logout Rest URL: - /api/v1/people/logout
Method:-POST Headers: Accept-Language: application/json API_KEY:
a5XSE8XCdsY6hAoCNojYBQ Content-Type: application/x-www-form-urlencoded
X-CSRF-Token: Parameters in body: username: e.g
service#test.com password: e.g. 123456
Use Interceptors for adding dynamic Header.
httpClient.addInterceptor((Interceptor.Chain chain) -> {
Request originalRequest = chain.request();
set OAuth token
Request.Builder newRequest = originalRequest.newBuilder();
newRequest.header("Authorization", accessToken).method(originalRequest.method(), originalRequest.body());
originalRequest = newRequest.build();
chain.proceed(originalRequest);
repeat request with new token
Response response = chain.proceed(originalRequest); //perform request, here original request will be executed
if (response.code() == 401) {
//if unauthorized
//perform all 401 in sync blocks
}
return chain.proceed(newRequest.build());
});
I´m looking for a solution to implement a JSON-POST request with OKHTTP. I´ve got an HTTP-Client.java file which handles all the methods (POST, GET, PUT, DELETE) and in the RegisterActivity I´d like to POST the user-data (from the input fields) JSON-formatted to the server.
This is my HTTP-Client.java
public class HttpClient{
public static final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
public static OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();
#Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
cookieStore.put(url.host(), cookies);
}
#Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = cookieStore.get(url.host());
return cookies != null ? cookies : new ArrayList<Cookie>();
}
})
.build();
public static Call post(String url, String json, Callback callback) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body.create(JSON, json))
.build();
Call call = client.newCall(request);
call.enqueue(callback);
return call;
}
}
... and this is the onClick-Part from the RegisterActivity
btnRegRegister.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//TODO
String registerData = "{\"email\":\"" + etRegisterEmail.getText().toString() + "\",\"password\":\"" + etRegisterPasswort.getText().toString() + "\"}";
try {
HttpClient.post(ABSOLUTE_URL, registerData, new Callback(){
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String resp = response.body().string();
if (resp != null) {
Log.d("Statuscode", String.valueOf(response.code()));
Log.d("Body", response.body().string());
}
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
Everytime I start the app it crashes when I click the Register-Button caused by a FATAL EXPECTION 'android.os.NetworkOnMainThreadException'
I´ve alread read something about the AsyncTask but I don´t know exactly how to do this.
Try my code below
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
Map<String, String> params = new HashMap<String, String>();
params.put("msisdn", "123123");
params.put("name", "your name");
JSONObject parameter = new JSONObject(param);
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(JSON, parameter.toString());
Request request = new Request.Builder()
.url(url)
.post(body)
.addHeader("content-type", "application/json; charset=utf-8")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.e("response", call.request().body().toString());
}
#Override
public void onResponse(Call call, Response response) throws IOException {
Log.e("response", response.body().string());
}
});
It's because you are trying to execute the HTTP query on the main thread (or UI thread). You shouldn't do a long task on the main thread because your app will hang, because the drawing routines are executed in that thread (hence his another name "UI Thread"). You should use another thread to make your request. For example:
new Thread(){
//Call your post method here.
}.start();
The Android asynctask is a simple class to do asynchronous work. It executes first his "onPreExecute" method on the calling thread, then his "doInBackground" method on a background thread, then his "onPostExecute" method back in the calling thread.
Try using Retrofit library for making Post request to the server. This provides a fast and reliable connection to the server.
You can also use Volley library for the same.
I have a post api to get some details. I am passing the parameters like this
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService github = retrofit.create(GitHubService.class);
Map<String, String> params;
Params.setAppContext(getApplicationContext());
params = Params.postCommuteParams(AppUtil.getAuthToken(MainActivity.this), android.os.Build.VERSION.RELEASE, "");
Log.d("retrofit param", ""+params.toString());
Call<CommuteResultVO> call1 = github.callCommute(params);
call1.enqueue(new Callback<CommuteResultVO>() {
#Override
public void onResponse(Response<CommuteResultVO> response, Retrofit retrofit) {
int statusCode = response.code();
CommuteResultVO user = response.body();
Log.d("retrofit", ""+statusCode+" );
}
#Override
public void onFailure(Throwable t) {
// Log error here since request failed
Log.d("retrofit", "failed");
}
});
}
The log for retrofit param gives all the params.
Log.d("retrofit param", ""+params.toString());
The params are working as this api call is completely working with volley.
This is how I have written the post call in GitHubService class
#FormUrlEncoded
#POST("/commutes/availability?")
Call<CommuteResultVO> callCommute(#FieldMap Map<String, String> parameters);
But I am getting a statusCode of 404 in the response