How to pass POST parameter in retrofit API method? - android

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);

Related

Read plain text response from server using Retrofit

I'm working on an application that uses Retrofit for network operations. As it stands, everything works well with GsonConverterFactory handling serialization. Here is how I setup Retrofit
Retrofit.Builder()
.baseUrl("<base url>")
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
Now I need to connect to a legacy service which returns content in text/plain; charset=utf-8 format. Here is the Retrofit interface
#GET("https://<domain>/<endpoint>?Type=Query")
suspend fun callStatus(#Query("userId") id: Int): Response<String>
This will return status of a call for a valid user. For instance, if the user is valid and there is a status, it returns "Active" as plain text. If there is no valid user, it returns an error code of #1005
I could add custom converter factory like this (found on the web)
final class StringConverterFactory implements Converter.Factory {
private StringConverterFactory() {}
public static StringConverterFactory create() {
return new StringConverterFactory();
}
#Override
public Converter<String> get(Type type) {
Class<?> cls = (Class<?>) type;
if (String.class.isAssignableFrom(cls)) {
return new StringConverter();
}
return null;
}
private static class StringConverter implements Converter<String> {
private static final MediaType PLAIN_TEXT = MediaType.parse("text/plain; charset=UTF-8");
#Override
public String fromBody(ResponseBody body) throws IOException {
return new String(body.bytes());
}
#Override
public RequestBody toBody(String value) {
return RequestBody.create(PLAIN_TEXT, convertToBytes(value));
}
private static byte[] convertToBytes(String string) {
try {
return string.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
}
But I didn't see it make any difference. Also, it could well disguise JSON as normal text and break all existing service. Is there a better way to handle this scenario? I thought of having separate retrofit instance for plain text, bit dirty though. Do you have any other suggestions/solutions?
Edited
Response header contains the content type as
Content-Type: text/plain; charset=utf-8
Actual response for valid user
Active
Actual response for invalid user
#1005
Update
The order in which you register the converter factories matters. ScalarsConverterFactory must come first.
it should be possible by adding ScalarsConverterFactory when building the Retrofit object.
This can be done alongside with other json converters, e.g.
Retrofit.Builder()
.baseUrl("<base url>")
.client(client)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
After that, you should be able to receive plaintext responses.
You probably need to add this to your dependencies as well:
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
The following is the way that how I get response as plain text (using Java not Kotlin).
Step One
in your gradle (Module);
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
Step Two
Create an interface
public interface MyInterface {
#GET("something.php")
Call<String> getData(#Query("id") String id,
#Query("name") String name);
}
Step Three
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://example.com")
.addConverterFactory(ScalarsConverterFactory.create())
.build();
MyInterface myInterface = retrofit.create(MyInterface.class);
Call<String> call = myInterface.getData("id","myname");
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
String plain_text_response = response.body();
}
#Override
public void onFailure(Call<String> call, Throwable t) {
}
});
You don't need to use a your custom implementation of Converter.Factory you could just use
// your coroutine context
val response = callStatus(userId)
if(response.isSuccessful){
val plainTextContent = response.body()
// handle plainText
} else {
//TODO: Handle error
}
//...
Two things to check first that function should not be suspended & your response should be in the Callback
No need to add extra implementation of scalars.
#GET
fun getJson(
#Url baseUrl: String = slab_pro
): Call<DataClass>

Why call have code 400 on response when postman doing it correct?

I want to provide clear code in accordance with the guidelines architecture and CleanCode rules.
I tried to use gson library to serialize data used in retrofit call.
I know that i can use #SerializedName in my model class but i want to learn how to use gson builder.
In MainActivity i have:
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CredentialModel credentials = new CredentialModel("User", "Password");
Gson gson = new GsonBuilder().serializeNulls().create();
String json = gson.toJson(credentials);
UserApiClient userApiClient = RetrofitInstace.getRetrofitInstance().create(UserApiClient.class);
Call<String> call = userApiClient.login(json);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
toastNotify(String.valueOf(response.code()));
}
#Override
public void onFailure(Call<String> call, Throwable t) {
toastNotify("Fail");
}
});
}
});
Interface UserApiClient:
#POST("/api/AppUser/login")
Call<String> login(#Body String credentials);
RetrofitInstance class:
public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(new OkHttpClient())
.build();
}
return retrofit;
}
I receive 400 error code when postman with data coppied from json variable in debug mode to body give me code 200. It isn't my serwer so i can't tell what is done on server side. Also im new in android and don't know how to check raw request in android studio yet.
You're using GsonConverterFactory.create() but you're passing String at Call<String> login(#Body String credentials); . You can't do that.
You need to pass in a POJO that is serialized by gson. Or else retrofit will pass in a null object as the body.
class MyBody {
// serialize it here
}
// You also cannot use a String at Call<String>
// for now use ResponseBody. Create a POJO class later though
Call<ResponseBody> login(#Body MyBody credentials);
What you want to do is already being done inside retrofit.
// retrofit does this for you underneat when you use GsonConverterFactory.create()
Gson gson = new GsonBuilder().serializeNulls().create();
String json = gson.toJson(credentials);

How to send post request with basic auth in retrofit?

In my code, I want to send post request with basic auth.
Here is my postman screenshot :
here is my apiInterface class
#FormUrlEncoded
#POST("GetBarcodeDetail")
Call<PreliminaryGoodsAcceptResponse> PRELIMINARY_GOODS_ACCEPT_RESPONSE_CALL(#Field("ProcName") String procName, #Field("Barcode") String barcode, #Field("LangCode") String langCode);
here is my apiclient
public class ApiClient {
public static final String BASE_URL = "http://192.**********";
private static Retrofit retrofit = null;
private static OkHttpClient sClient;
public static Retrofit getClient() {
if(sClient == null) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
sClient = new OkHttpClient.Builder()
.addInterceptor(new HttpLoggingInterceptor(HttpLoggingInterceptor.Logger.DEFAULT))
.addInterceptor(interceptor)
.build();
}
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(sClient)
.build();
}
return retrofit;
}
}
My question is how can i send post request,using header :
Header Username : EBA Token :
34242353453456563DSFS
This is so far the easiest method i have ever tried for "Basic Authentication".
Use the below code to generate the auth header (API/Repository class)
var basic = Credentials.basic("YOUR_USERNAME", "YOUR_PASSWORD")
Pass this as header to the webservice call (API/Repository class)
var retrofitCall = myWebservice.getNewsFeed(basic)
Add the basic header as parameter (Retrofit Webservice interface class)
#GET("newsfeed/daily")
fun getNewsFeed(#Header("Authorization") h1:String):Call<NewsFeedResponse>
Sorry, my code is in Kotlin, but can be easily translated to Java.
References: https://mobikul.com/basic-authentication-retrofit-android/
make header like this way..
private Retrofit getClient(final Context context) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.readTimeout(60, TimeUnit.SECONDS);
client.writeTimeout(60, TimeUnit.SECONDS);
client.connectTimeout(60, TimeUnit.SECONDS);
client.addInterceptor(interceptor);
client.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (context == null) {
request = request
.newBuilder()
.build();
} else {
request = request
.newBuilder()
.addHeader("Authorization", "Bearer " + AppSetting.getStringSharedPref(context, Constants.USER_KEY_TOKEN, ""))
.build();
}
return chain.proceed(request);
}
});
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client.build())
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit;
}
Use Header annotation
#FormUrlEncoded
#POST("GetBarcodeDetail")
Call<PreliminaryGoodsAcceptResponse> PRELIMINARY_GOODS_ACCEPT_RESPONSE_CALL(#Header("Authorization") token: String,#Field("ProcName") String procName, #Field("Barcode") String barcode, #Field("LangCode") String langCode);
Simple-Retrofit-API-request-and-Data-Loading Here I just add the project where create the API call to access data from database using retrofit library; which is leading library to access data on network. And display the accessed data in the List format. Create the Simple Android Studio Project with Empty Activity. Create the Adapter and activity item to show normal lists in android app. Now Create the App class extending Application, as Application class is a singleton that you can access from any activity or anywhere else you have a Context object.
You can check the more details about Application class from https://github.com/codepath/android_guides/wiki/Understanding-the-Android-Application-Class Why extend an Application class? https://developer.android.com/reference/android/app/Application.html
Add android:name=".YourApplication" i.e. class name extending the Application class in android. and class will be like public class YourApplication extends Application Init the Retrofit in Application class
//network code start
//init http logger
httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
// init client client = new OkHttpClient.Builder()
.addInterceptor(httpLoggingInterceptor)
.addInterceptor(new Interceptor() {
#Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request request2 = request.newBuilder().build();
return chain.proceed(request2);
}
}).connectTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).build();
Gson gson = new GsonBuilder().setLenient().create();
Retrofit mRetrofit = new Retrofit.Builder().baseUrl(Constants.API_BASE_URL).client(client).addConverterFactory(GsonConverterFactory.create(gson)).build();
mWebservice = mRetrofit.create(Webservice.class);
While Constants.API_BASE_URL is base url Create the Webervice.class where you can call the API with parameters e.g. In case of GET Method:
#GET("webservices/GetAllClientsDemoRetro.php")
Call updateChatStatus();
In case of POST method:
#FormUrlEncoded
#Headers({"Content-Type: application/x-www-form-urlencoded"})
#POST("webservices/GetAllClientsDemoRetro.php")
Call updateChatStatus();
You can See the more in details About Retrofit on Official API declaration here: http://square.github.io/retrofit/
We can parse the values with POJO i.e. Setter and Getter, using the Parceble class. Since parsing key name should be equal to the value we are receiving from the JSON response. POJO class should be declared like public class ClientData implements Parcelable { then declare the keys in the class, key values means
public class ClientData implements Parcelable
{
public String client_id;
public String company_name;
public String address_line;
public String city;
public String pincode;
public String state;
public String country;
}
Now using Alt+Enter i.e. select the option Add Parceble Implementation and press enter. Then automatically parceble class will be added. Also you have to add Setter and Getter method in class using Alt + Insert. Note: Don’t add the Setter and Getter methods for CREATER: Creater<> method If you want to use different key that JSON response key, then you should use Serialization. When I was using same key then its is like public String client_id; But when I am using the Serialization, then I can use like #Serializattion(“client_id”) public String ClientID; Now last but not a list, We call the API using retrofit, and use the response to view the Item in list-
RetroFitApplication.getWebservice().updateChatStatus().enqueue(new Callback() {
#Override public void onResponse(Call call, Response response) {
Log.d("retrofilt success", "" + response.body());
if (response.body() != null) {
clientResponceData = response.body();
Gson gson = new Gson();
String body = gson.toJson(response.body());
Log.d("retrofilt success2", "clientData" + clientResponceData.getResponse());
if (clientResponceData.getResponse() != null) {
initRV();
}
} else {
// Empty Client List Toast.makeText(ClientList.this, "Empty List", Toast.LENGTH_SHORT).show();
}
}
#Override public void onFailure(Call call, Throwable t) {
Log.d("retrofilt error", "" + t);
Toast.makeText(ClientList.this, "No Internet Connection", Toast.LENGTH_SHORT).show();
}
});
By using the Construction in Adapter, we can use the values from the response. Guys I added this repository to get the Entire idea of calling the API and get the response from server using the Retrofit Library. I write this entire documents in details with simple word.

How can i POST json data in Android

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

Retrofit: How do I go about downloading images? + Some other questions

I am currently looking into implementing the Retrofit API (after using Volley) into my app and I have some questions that I cannot seem to find answers to anywhere else so I will ask here.
How do I go about downloading images using Retrofit API? I am asking this because Volley has the ImageLoader class and NetworkedImageView etc. and was wondering if Retrofit has something similar?
I read that using the RequestIntercepter, it can add a header to every request. How is this different from just adding a static (or dynamic) header (#Header) in the interface's abstract method
How does Retrofit deal with nested JSON objects? I read it uses GSON to convert the JSON into java objects but the POJO class must have the same field names.
Thank you for reading
For your first doubt:
Retrofit no have feature to manager image as Volley and UIL has. The same company that developer Retrofit too have a nice lib to manager images called Picasso.
For your second doubt:
Headers that need to be added to every request can be specified using
a RequestInterceptor. The following code creates a RequestInterceptor
that will add a User-Agent header to every request.
for instance:
I developed a client to Parse.com and to all request I need set my keys in the header: see here Android-Retrofit-Example
public class RestClient {
private static RestClient mRestClient = null;
private static RestAdapter restAdapter;
private static RequestInterceptor requestInterceptor;
public static RestClient getInstance(){
if(mRestClient == null ){
mRestClient = new RestClient();
setup();
}
return mRestClient;
}
private static void setup(){
requestInterceptor = new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
request.addHeader("X-Parse-Application-Id", "");
request.addHeader("X-Parse-REST-API-Key", "");
}
};
restAdapter = new RestAdapter.Builder()
.setEndpoint(" https://api.parse.com/1/")
.setLogLevel(RestAdapter.LogLevel.FULL)
.setRequestInterceptor(requestInterceptor)
.build();
}
public RestAdapter getRestAdapter(){
return restAdapter;
}
}
The last :
JSON CONVERSION
Retrofit uses Gson by default to convert HTTP bodies to and from JSON.
If you want to specify behavior that is different from Gson's defaults
(e.g. naming policies, date formats, custom types), provide a new Gson
instance with your desired behavior when building a RestAdapter. Refer
to the Gson documentation for more details on customization.
To get this :
{
results: [3]
{
createdAt: "2015-03-07T20:43:44.107Z"
objectId: "osCJ8PI65r"
updatedAt: "2015-03-08T00:45:37.539Z"
username: "Test 2"
},
{
createdAt: "2015-03-07T21:42:38.591Z"
objectId: "tkIi6Ll1Os"
updatedAt: "2015-03-07T21:42:38.591Z"
username: "Test 2"
},
{
createdAt: "2015-03-08T01:13:21.188Z"
objectId: "Cz0HqiYpwl"
updatedAt: "2015-03-08T04:21:18.069Z"
username: "Test 3"
}
}
Pojo :
public class User {
private String objectId;
private String username;
private String createdAt;
private String updatedAt;
//gerate getters and setters
}
public class WrappeUser {
#SerializedName(value="results")
List<User> results;
public List<User> getResults() {
return results;
}
public void setResults(List<User> results) {
this.results = results;
}
}

Categories

Resources