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?
Related
I am using the retrofit library for API call and I want to send the parameter to my server using the "form-data" method. I found this question on StackOverflow, but there is no solution yet. Please guide me and let me know if I can provide more details for the same. Thank you
Why don't you use Multipart?
This is an example of using it for a simple user info with phone number, password and a prfile pic:
In your Activity:
final RequestBody rPhoneNumber = RequestBody.create(MediaType.parse("text/plain"), "sample phone number");
final RequestBody rPassword = RequestBody.create(MediaType.parse("text/plain"), "sample phone password");
final MultipartBody.Part rProfilePicture = null;
Retrofit.Builder builder = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create()).baseUrl(baseUrl).client(Cookie.cookie.build());
Retrofit retrofit = builder.build();
final RequestHandler requestHandler = retrofit.create(RequestHandler.class);
rProfilePicture = MultipartBody.Part.createFormData("file", file.getName(), RequestBody.create(MediaType.parse("image/*"),file)); //sample image file that you want to upload
Call<ServerMessage> call; //ServerMessage is a class with a String to store and convert json response
call = requestHandler.editProfile(rPhoneNumber, rPassword, rProfilePicture); //editProfile is in RequestHandler interface
call.enqueue(new Callback<ServerMessage>() {
#Override
public void onResponse (Call < ServerMessage > call2, Response < ServerMessage > response){
//your code here
}
#Override
public void onFailure (Call < ServerMessage > call, Throwable t) {
//your code here
}
});
In RequestHandler.java interface:
#Multipart
#POST("/api/change-profile")
Call<ServerMessage> editProfile(#Part("phoneNumber") RequestBody rPhoneNumber,
#Part("oldPassword") RequestBody rPassword,
#Part MultipartBody.Part rProfilePicture);
In ServerMessage.java:
public class ServerMessage {
private String message;
public String getMessage() {
return message;
}
}
This sample should help:
public interface AuthService {
#POST("register")
#Headers("Content-Type:application/x-www-form-urlencoded")
#FormUrlEncoded
Call<LoginResponse> loginSocial(#Field("provider") String provider, #Field("access_token") String accessToken }
I know this might be late. I came this same challenge and this is what works for me
val requestBody: RequestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("avatar", imageFile.toString())
.build()
#POST("avatar")
fun uploadProfilePicture(
#Header("Authorization") header: String?,
#Body avatar:RequestBody
): Call<UserResponse>
I am using Retrofit2 to send and receive requests to my server.
Here are my API interface and Model class.
Interface
public interface ApiInterface {
#POST("/users/")
Call<User> signUp(#Body User user);
#POST("/login_url/")
Call<User> login(#Body User user);
}
Retrofit client
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getRestClient(String baseUrl) {
if (retrofit == null) {
retrofit = new Retrofit.Builder().baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
POJO class
public class User {
#SerializedName("id")
private Integer id;
#SerializedName("email")
#Expose
private String email;
#SerializedName("first_name")
private String firstName;
#SerializedName("last_name")
private String lastName;
#SerializedName("password")
#Expose
private String password;
}
I have exposed email and password so that in login request these 2 parameters will be added.
But for another request like Sign up, I required a first name and last name also to be sent along with email and password.
Can I use same "User" class for both ? because if I expose the first name and last name then, those fields will be also sent in login request.
Is there any other way or should I make different POJO classes for both request ?
Instead of sending the whole class , you can use #Field annotation , so your login callback will be something like this :
#FormUrlEncoded
#POST("/login_url/")
Call<User> login(#field("email")String email,#field("password")String password);
#FormUrlEncoded denotes that the request body will use form URL encoding. Fields should be declared as parameters and annotated with #Field.
Can I use same "User" class for both ?
Yes , you can use the same Model as #Body for both requests !
Just make sure where you don't need the required variables just omit them !!
Remove the #SerializedName and #Expose , these are not required and give the variable names according to the json KEYs
public class User {
private Integer id;
private String email;
private String firstName;
private String lastName;
private String password;
}
Edit
Suppose for example , for one request you need :-
4 params you set the model user as
new User(id,email,firstname,lastname); // dont init the password attribute
5 params you set all values to the model like
new User(id,email,firstname,lastname,password);
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?
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¶m=%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);
}
}
I m trying to make a request in which I want to include a Header , a form-urlencoded field and a json body.
My Retrofit interface is as follows
#FormUrlEncoded
#POST("/api/register")
Observable<RegisterResponse> register(
#Header("Authorization") String authorization,
#Field("grant_type") String grantType,
#Body RegisterBody body
);
When I make this request I get back exception #Body parameters cannot be used with form or multi-part encoding.
I have also tried with the #Multipart annotation:
#Multipart
#FormUrlEncoded
#POST("/api/register")
Observable<RegisterResponse> register(
#Header("Authorization") String authorization,
#Part("grant_type") TypedString grantType,
#Body RegisterBody body
);
and I get an IllegalArgumentException and only one encoding annotation is allowed.
maybe this could help some people, if you have this trouble, you should remove #FormUrlEncoded of your interface.
This post pointed me to the right direction https://stackoverflow.com/a/21423093/1446856.
I attached everything in the body and send it as a TypedInput.
So the interface looks something like this
#POST("/api/register")
#Headers({ "Content-Type: application/json;charset=UTF-8"})
Observable<RegisterResponse> register(
#Header("Authorization") String authorization,
#Body TypedInput body
);
and the body looks something like this
String bodyString = jsonBody + "?grant_type=" +
grantType + "&scope=" + scope;
TypedInput requestBody = new TypedByteArray(
"application/json", bodyString.getBytes(Charset.forName("UTF-8")));
Adding to Julien's answer, also remove the #Multipart annotation. Here's how I have used it:
#POST("/app/oauth/token")
Call<AuthResponse> getAuthToken(#Body RequestBody body);
And, here is how I have constructed the RequestBody:
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("grant_type", "password")
.addFormDataPart("username", username)
.addFormDataPart("password", password)
.build();
I solved this problem by adding the field into
#POST("/api/register")
like this:
#POST("/api/register?grantType=value")
it's not a good solution, but may be useful.
Send Authentication header with json Body to API sample code in Kotlin :
#POST("/api/user/sendlist/")
fun callSendJsonListPost(
#Header("Authheader") header: String,
#Body list: StringBuilder
)
: Observable<EntityModelUserslist>