retrofit post response is incorrect - android

this is how to call login method.
public static Observable<ResponseBody> login(String id, String password) {
ApiService apiService = ApiServiceGenerator.generate(ApiService.class);
return apiService.login("%2F", id, password)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.unsubscribeOn(Schedulers.io());
}
and this is interface
#FormUrlEncoded
#POST("/login_check")
Observable<ResponseBody> login(#Field("url") String url, #Field("mb_id") String id, #Field("mb_password") String password);
there "%2F" is <input type="hidden" name="url" value="%2F"> in html
in Postman chrome extension, i could success to login.
but in android, i couldn't.
What did I miss?

Related

Retrofit2 Replacing query parameters

I am using Retrofit2 and sending request with input parameters as follows. But retrofit automatically converts + symbol to %2B. How to encode this and send as + itself
Relevant code
1) Interface
#POST("/registrationapi.php")
Call<RegistrationPOJO> registrationResponse(#Query("firstname") String firstname , #Query("lastname") String lastname,
#Query("email") String email, #Query("password") String password,
#Query("uid") String uid, #Query("mobile") String mobile,
#Query("key") String key
);
2) RestClient
private APIInterface service;
public RestClient() {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(logging);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(AppConfiguration.BASEURL)
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build())
.build();
service = retrofit.create(APIInterface.class);
}
public void getRegistrationInfo(final Registration context, String firstname, String lastname, String email,
String password, String uid, String mobile, String key
){
Call<RegistrationPOJO> reg =service.registrationResponse(firstname,lastname,email,password,uid,mobile,key);
reg.enqueue(
new Callback<RegistrationPOJO>() {
#Override
public void onResponse(Call<RegistrationPOJO> call, Response<RegistrationPOJO> response) {
success = response.isSuccessful();
if(success) {
//Handle success flow
} else {
//Handle error flow
}
}
#Override
public void onFailure(Call<RegistrationPOJO> call, Throwable t) {
//Handle error flow
}
}
);
}
My mobile number is having + symbol at the beginning. From the
retrofit logs, I can see this is converted like
mobile=%2B11111111111 while sending the request.
I am expecting encoding and making input parameter like
mobile=+11111111111
Corresponding gradle dependencies are
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
As per anurag's suggestion. I have changed parameter to
#Query(value = "mobile" , encoded=true) String mobile
and its working as expected
Try using encoded = true in query params.
Call<ResponseBody> method(#Query(value = "+11111111111", encoded = true) String mobile) {
.....
}

Retrofit 2 response body

I am trying to get a bearer token from Twitter's oauth. I make a #POST to base url https://api.twitter.com which looks like this:
#Headers({ "Content-Type: application/x-www-form-urlencoded;charset=UTF-8"})
#FormUrlEncoded
#POST("/oauth2/token") Observable<Result<BearerToken>> getBearerToken(
#Field("grant_type") String grantType,
#Header("Authorization") String authorization);
My BearerToken model class is:
public class BearerToken {
public String getAccessToken() {
return accessToken;
}
#SerializedName("access_token")
String accessToken;
}
However, I am trying to parse the Result of Result<BearerToken> bearer, by calling bearer.response().body().getAccessToken(), but logcat says it is null.
Any ideas?

How to handle the `IllegalArgumentException` in RxJava?

I'm using Retrofit with RxJava for the network calls and RxBinding for view operations. In signup screen, upon clicking 'Register' button I'm posting the info to the local server using the MyApi service.
SignupActivity.class
mCompositeSubscription.add(RxView.clicks(mRegisterButton).debounce(300, TimeUnit.MILLISECONDS).
subscribe(view -> {
registerUser();
}, e -> {
Timber.e(e, "RxView ");
onRegistrationFailed(e.getMessage());
}));
private void registerUser() {
mCompositeSubscription.add(api.registerUser(mEmail,
mPassword, mConfirmPassword)
.subscribe(user -> {
Timber.d("Received user object. Id: " + user.getUserId());
}, e -> {
Timber.e(e, "registerUser() ");
onRegistrationFailed(e.getMessage());
}));
}
MyApi.class
public Observable<User> registerUser(String username, String password, String confirmPassword) {
return mService.registerUser(username, password, confirmPassword)
.compose(applySchedulers());
}
#SuppressWarnings("unchecked") <T> Observable.Transformer<T, T> applySchedulers() {
return observable -> observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
MyService.class
#FormUrlEncoded #POST("users/")
Observable<User> registerUser(#Path("email") String username,
#Path("password") String password, #Path("password_confirmation") String confirmPassword);
The call fails with IllegalArgumentException since I'm posting an invalid info.
What's my main issue is, upon IllegalArgumentException I thought RxJava would execute registerUser()#ErrorHandler() since my registerUser service call failed with exception but instead it calls RxView#ErrorHandler().
How can I make/force registerUser()#ErrorHandler() to take care of the exception occurred during the network call?
My bad, the network call doesn't fail with IllegalArgumentException but the request construction itself failed with IllegalArgumentException.
java.lang.IllegalArgumentException: URL "users/" does not contain {email}".
Instead of using #Field annotation for constructing the POST body , I'd mistakenly used #Path annotation.
The correct definition:
#FormUrlEncoded #POST("users/")
Observable<User> registerUser(#Field("email") String username,
#Field("password") String password, #Field("password_confirmation") String confirmPassword);

Retrofit post request with JsonObjectField

I need send post requests like this:
{
"request": "AppStart",
"appKey": "d7ea9ac1-8eb0-44f8-809d-bff6944db6c7",
"param" : {
"somedata" : "data"
},
"buildId": "111111111-1111-1111-1111-11111111111"
}
I write simple function for register appllication:
public interface RestClient {
#Headers("Content-Type: application/json" )
#FormUrlEncoded
#POST("/")
<T> void callMethod(
#Field("request") String method,
#Field("appKey") String key,
#Field("param") JsonObject params,
);
public void registerUser(String key, string userID) {
JsonObject params = new JsonObject().putProperty("userId" userID);
api.callMethod("registerUser", key, params);
}
this is retrofit log:
request=registerUser&appKey=123bff6944db6c7&param=%7B%22deviceUdid%22%3A%2276839a55470a2cd4%22%7D
How to fix my code?
In your registerUser method build an object that reflects the desired JSON structure and then use Retrofit's #Body annotation.
public void registerUser(String key, string userID) {
CallMethodBody callMethodBody = ...
api.callMethod(callMethodBody);
}
public interface RestClient {
#Headers("Content-Type: application/json" )
#FormUrlEncoded
#POST("/")
<T> void callMethod(#Body CallMethodBody callMethodBody);
}
That will send the whole JSON string as the body of your POST request.
Instead of #Field you should use #Body.
Request Body
An object can be specified for use as an HTTP request body with the
#Body annotation.
#POST("/users/new")
void createUser(#Body User user, Callback<User> cb);
The object will also be converted using the RestAdapter's converter.
Reference: http://square.github.io/retrofit/
You need to create class which will represent your request body, e.g.:
public class Data {
String request;
String appKey;
String buildId;
Param param;
}
public class Param {
String somedata;
}
Next you can use this class as request body:
public interface RestClient {
#Headers("Content-Type: application/json")
#FormUrlEncoded
#POST("/")
<T> void callMethod(#Body Data data);
public void registerUser(Data data) {
api.callMethod(data);
}
}

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