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);
Related
I just want to send back an attribute that was not defined in POJO class.
My POJO class is this
public class PostData {
#SerializedName("Token")
#Expose
private String token;
#SerializedName("Amount")
#Expose
private Integer amount;
#SerializedName("AuthID")
#Expose
private String authID;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public Integer getAmount() {
return amount;
}
public void setAmount(Integer amt) {
this.amount = amt;
}
public String getAuthID(){return authID;}
public void setAuthID(String authID){
this.authID = authID;
}
}
Amount,Token,AuthID are sent from the client side to API.Here I used HTTP Cloud function as an HTTP POST.I need to send back the TransID to client side which is not there in POJO class.In client side I need to read the response and store it.
Here is my cloud function code:
exports.Add = functions.https.onRequest((req,res)=>{
//var testPublicKey = [xxxxxxxxxxxxxxxxx]
var stripe = require("stripe")("stripe_key");
console.log("Token:"+req.body.Token)
console.log("Amount:"+req.body.Amount)
var tokenToCharge = req.body.Token;
const amountToCharge = req.body.Amount;
var authID = req.body.AuthID;
const databaseRef = admin.firestore();
const payer = databaseRef.collection('deyaPayUsers').doc(authID).collection('Wallet').doc(authID);
const balance = payer.Usd
stripe.charges.create({
amount : amountToCharge,
currency : "usd",
description : "charge created",
source : tokenToCharge,
}, function(err, charge) {
if(charge.status === "succeeded"){
var trans = databaseRef.runTransaction(t=>{
return t.get(payer)
.then(doc=>{
var updatedBalance = doc.data().Usd + parseInt(charge.amount);
t.update(payer,{Usd : updatedBalance});
});//return close
}).then(result=>{
console.log('Transaction success!');
}).catch(err=>{
console.log('Transaction Failure:',err);
});
}
});
});//end of stripe create charge
you add one field in pojo class using transient key is ignore a value to send api call and get client side value.
transient
private String TransID;
and make getter and setter method.
is there any reason why you do not want to create a variable for the TransID in your POJO class? I understand that your POJO class interacts with your Client Side of your application. Hence, having a variable for the TransID(with getters and Setters) will give you more flexibility to read the response and store it as you want.
To read response using Retrofit have a separate class(which is here PostData) that represents the outputs of the JSON response which we get when a request was served by the backend.create an interface class and with #Method(GET, POST, DELETE etc;) annotation and pass parameters to the method.In client-side pass the parameters to the method and get the response by calling the getmethod of the parameter you are expecting.
I am using Retrofit to send and receive requests to my server.
I Have a model like below and I have to send it to my server but some variables in this model have not to send to the server.
public class SelectedListModel implements Serializable {
#SerializedName("p_id")
#Expose
private Long pId;
#SerializedName("p_qty")
#Expose
private Double pQty;
#Expose(serialize = false , deserialize = false)
private String pName; //Have not to send to server
#Expose(serialize = false , deserialize = false)
private String pPrice; //Have not to send to server
#Expose(serialize = false , deserialize = false)
private String pImageUrl; //Have not to send to server
}
and because of that, I am getting 400 in my responses from the server.
I used of #Expose(serialize = false, deserialize = false) in order to Ignore variables that have not to send to the server.
But it doesn't work.
Is there any way to do this or I have to create another model just for my server?
Use transient keywork for that
public class SelectedListModel implements Serializable {
#SerializedName("p_id")
#Expose
private Long pId;
#SerializedName("p_qty")
#Expose
private Double pQty;
//#Expose(serialize = false , deserialize = false)
private transient String pName; //Have not to send to server
//#Expose(serialize = false , deserialize = false)
private transient String pPrice; //Have not to send to server
//#Expose(serialize = false , deserialize = false)
private transient String pImageUrl; //Have not to send to server
}
and no need to use #Expose(serialize = false , deserialize = false), into those fields which needed to be excluded.
Read Why does Java have transient fields? and Why use the `transient` keyword in java? for more details.
You can use transient keyword to ignore fields when requesting api calls
JAVA:
transient String name;
KOTLIN:
#Transient
var name: String
change your Retrofit adapter code like this (I hope you're using retrofit2)
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
In my application I want POST some data, and this data get users and POST to server. For server requests I use Retrofit2.
For POST this data I should POST with json format, such as this :
{
"email": "example#example.com",
"username": "example",
"password": "123",
}
After POST data I should check with this results for submit data has Ok ro Not.
{
"status": 200,
"Message": "",
"data": true
}
I give Email, Username and Password with EditText from users, but how can I POST this data to server with Json format?
Please help me, I am amateur and I really need this help
Firstly, create a class for your request, for example, LoginRequest.java
public class LoginRequest {
private String email;
private String username;
private String password;
//getters and setters
}
Secondly, create a class for your response, LoginResponse.java
public class LoginResponse {
private Integer status;
private String Message;
private Boolean data;
//getters and setters
}
Finally, in your interface add this method:
public interface MiApiInterface {
#POST("yourResourceName") Call<LoginResponse> login(#Body LoginRequest request);
}
I hope It could help you, just ask me if you have more question.
have you realised that the return of the login method is a Call, it is for a async call, you could use it like this on your activity:
firstly, create a retrofit instance
Retrofit retrofit = ....
Secondly, create your interface instance like this:
MiApiInterface apiInterface = retrofit.create(MiApiInterface.class);
Finally, you could access the login method:
LoginRequest request = new LoginRequest();
request.set();
....
Call<LoginResponse> responseCall = apiInterface.login(request);
responseCall.enqueue(new Callback<LoginResponse>() {
public void onResponse(...){
LoginResponse loginResponse = response.body();
}
public void onFailure(...){
}
}
To Convert Objects to Json automatically, you should add a Converter Factory on your retrofit builder:
Gson gson = new GsonBuilder().create();
Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create(gson))
...
dont forget import the Gson library on your gradle.
Here is a tutorial on Retrofit 2: http://www.vogella.com/tutorials/Retrofit/article.html
Alternatively, you can use Volley, it is a library specificaly designed to make http requests on Android. https://developer.android.com/training/volley/index.html
I am writing my first code in Retrofit 1.9 version. I tried to follow several blog but not able to understand very basic problem. So far, I have created Model class using jsonschema2pojo, RestAdapter class.
Here is my model class:
#Generated("org.jsonschema2pojo")
public class GmailOauth {
#Expose
private String createdAt;
#Expose
private String objectId;
#Expose
private String sessionToken;
#Expose
private String username;
..... Getter and Setter methods...
I have created above model class using Jsonschema2pojo. So, my response JSON is very understandable.
Adapter class
public class RestApiAdapter {
public static final String BASE_URL = "http://testingserver.com:8081";
public RestAdapter providesRestAdapter(Gson gson) {
return new RestAdapter.Builder()
.setEndpoint(BASE_URL)
.build();
}
}
API class
interface GmailSignInAPI {
#POST("/signWithGmail")
void GmailOauthLogin(#Body GmailOauth user, Callback<GmailOauth> cb);
}
Now, I am confused how to write Retrofit client to pass following form-data post parameter in efficient way?
accessToken (String value)
userID (String value)
How about if I want to pass custom object in a post request and save the response of request in same object? Is this good way to do it?
I think for the api portion of Retrofit I would put
#FormUrlEncoded
#Post("/path/to/whatever")
void authenticateWithSomeCredentials(#Field("username") String userName, Callback<Object> reponse
Then I would call it like this:
public void authenticateWithSomeCredentials(username), new Callback<Object>() {
#Override
public void success(Object object, Response response) {
// Do something
}
#Override
public void failure(RetrofitError error) {
// Do something
}
}
To add the token to every call you could add an interceptor:
public class YourAuthInterceptor implements interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
request = chain.request().newBuilder()
.addHeader("token"), tokenVariable)
.build();
return chain.proceed(request);
}
}
this will add a "token" to every call you make with retrofit
so then when you build your api you build it like this
YourApi api = new RestAdapter.Builder()
.setEndpoint(url)
.setRequestInterceptor(new YourAuthInterceptor())
.build()
.create(YourApi.class);
I hope this makes sense as I am typing it rather quickly. If you have any questions please let me know.
You can do it like this:
#FormUrlEncoded
#POST("/postTosServer")
void postToServer(#Field("accessToken") String your_token, #Field("userID") String userid);
I'm working on API Requests with Retrofit(1.9.0) and gson library (1.7.0 I have compatibility issues with version 2.3.1 of gson) on Android, I make some request to an API which have same format of response but different content following the url call, but I encounter a problem for a deserialization of one answer which there is array inside. This is an example of the json I want to deserialize :
{
"http_code":200,
"content":[
{
"name":"Groult Christian",
"location":[
48.897655,
2.252462
],
"website":null,
"address":{
"street_address":"XXXXXX",
"city":"XXXXXX",
"state":null,
"postal_code":"XXXXXX",
"country":"XXXXXX"
},
"global_score":0,
"popularity_score":0,
"quality_score":0,
"createdAt":"2015-02-18T02:13:05.068Z",
"updatedAt":"2015-02-18T02:13:05.068Z",
"id":"54e3f531775288ca572872ac"
},
...
]
}
My DeserializerJson and how I call it for retrofit:
public class DeserializerJson<T> implements JsonDeserializer<T> {
#Override
public T deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
throws JsonParseException
{
// Get the "content" element from the parsed JSON
JsonElement content = je.getAsJsonObject().get("content");
// Deserialize it. You use a new instance of Gson to avoid infinite recursion
// to this deserializer
return new Gson().fromJson(content, type);
}
}
...
Gson gson = new GsonBuilder()
.registerTypeAdapter(ContentUser.class, new DeserializerJson<ContentUser>())
.registerTypeAdapter(DeviceInfo.class, new DeserializerJson<DeviceInfo>())
.registerTypeAdapter(PlacesModel.class, new DeserializerJson<PlacesModel>())
.create();
RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.BASIC)
.setConverter(new GsonConverter(gson))
...
...
and my different models:
public class PlacesModel {
#SerializedName("name")
#Expose
private String name;
#SerializedName("location")
#Expose
private List<Double> location = new ArrayList<Double>();
#SerializedName("website")
#Expose
private Object website;
#SerializedName("address")
#Expose
private AddressModel address;
#SerializedName("global_score")
#Expose
private Integer globalScore;
#SerializedName("popularity_score")
#Expose
private Integer popularityScore;
#SerializedName("quality_score")
#Expose
private Integer qualityScore;
#SerializedName("createdAt")
#Expose
private String createdAt;
#SerializedName("updatedAt")
#Expose
private String updatedAt;
#Expose
#SerializedName("id")
private String id;
/* Getters and Setters... */
}
public class AddressModel {
#SerializedName("street_address")
#Expose
private String streetAddress;
#SerializedName("city")
#Expose
private String city;
#SerializedName("state")
#Expose
private Object state;
#SerializedName("postal_code")
private String postalCode;
#SerializedName("country")
#Expose
private String country;
/* Getters and Setters... */
}
url call in Api Manager is like this:
#GET("/places")
public void getPlaces(RestCallback<List<PlacesModel>> callback);
But when I do the call I get this error : com.google.gson.JsonParseException: The JsonDeserializer com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter#3b8aa06 failed to deserialize json object
Everything is fine for other call I get all content and so with no problem but one where there is array inside content I got an error and I don't understand why I believed if I just put a list of my model it will be fine but it doesn't work.
I think I miss something so if someone can help me
Thanks in advance
The problem of your issue is that you register DeserializerJson for PlacesModel class and in getPlaces method your response is List<PlacesModel> class. List<PlacesModel> is a different class as PlacesModelso Gson doesn't know how to deserialise List<PlacesModel>. What you have to do is register one more Deserialiser by this method:
.registerTypeAdapter(List.class, new DeserializerJson<List<PlacesModel>>())
If you use more than one type of List (I mean List<PlacesModel> and List< DeviceInfo >) You can define your own TypeAdapter or you cN change list to array and register deserialiser for them as is shown below
.registerTypeAdapter(PlacesModel[].class, new DeserializerJson<PlacesModel[]>())
Now everything works fine for yours json.