Where in Retrofit build the full JSON before sending it? - android

I am using retrofit an get Bad Request , I would want to know if there is a place in this library where builds the full JSON in string format before sending it.

If it's about inspecting the JSON at runtime for debugging purposes, you can call setLogLevel(LogLevel.FULL) on your RestAdapter.Builder.
FULL logs the headers, body and metadata for both requests and responses to logcat.

new String(((TypedByteArray) request.getBody()).getBytes());

In order to build a JSON formatted body, create an object with a class whose properties are the same that you want to send to the server. The GSON Library set up (or whichever library you are using) with the RestAdapter should send the request with the body in JSON format.
Also ensure that the call is #POST annotated and the parameter annotd with #Body Below is an example:
#POST("/login")
User login(#Body LoginUser loginUser);

Related

What is the difference between #Field and #Query in retrofit

In some POST requests, I don't know when to use #Field with FormUrlEncoded and when to use #Query
For Example:
#POST("list-products-for-sale")
Call<ListAllProductsResponse> getNewProducts(#HeaderMap Map<String,
String> headers,#Query("lastProductId") String lastProductId);
When I tried to use #Field here it was not responding properly and when I switched it to #Query it's working great.
I want to know why #Field isn't working while Query can work perfectly and I did tested in POSTMAN where I sent the data as a formurlencoded and it's giving me the results fin.
EDIT
BTW I'm passing Content-Type:application/json, Accept: application/json with an Authorization key
#Field is used to send #FormUrlEncoded request in Retrofit which hides your parameter and not attach with url to provide security.Used for POST request.
#Query parameter appended to the URL.
If you are using #Field request than it will hides your parameter and not append with the url.
If you are using #Query request than all your parameter is append to your request and visible to users.
Depend on your api request you have to use one of above annotation. If the api request accept the #FormUrlEncoded data than use #Field or if they want to attached it with url than use #Query.
You can get more information from below link :
1) https://square.github.io/retrofit/2.x/retrofit/index.html?retrofit2/http/Query.html
2) https://square.github.io/retrofit/2.x/retrofit/retrofit2/http/Field.html

How to read custom header response (json object) in retrofit

I have an authorization api that returns null body but with access token in headers.
I am able to read the okhttp3.Headers object and also get header names as Set using
Headers headers = response.headers(); // response object of type Response<T>
Set<String> headerNames = headers.names();
But in the code the headers object does not show the custom header (access_token) returned as response. However, in postman i can see the custom header as shown below:
access_token -> { "Token":"adklasldalksdalkdask",
"Provider":"ABC" }
I am using interceptors to get the header as shown:
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
Can someone suggest how to read the access token as part of the custom header in auth response?
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.

Why Post method of okhttp occur error [Content-Type header specified in HTTP request is not supported: application/x-www-form-urlencoded]?

I call a Rest API of salesforce by post method:
url = "https://test-dev-ed.my.salesforce.com/services/apexrest/AccountUsers/"
client = OkHttpClient()
val jsonIn = FormBody.Builder()
.add("email",URLEncoder.encode("dt1#gmail.com", "UTF-8"))
.add("password", URLEncoder.encode("1","UTF-8"))
.build()
request = Request.Builder()
.post(jsonIn)
.header("Authorization", "Bearer "+accesstoken)
.addHeader("Content-Type","application/x-www-form-urlencoded")
.url(url)
.build()
response = client.newCall(request).execute()
This is rest api:
#HttpPost
global static ID createUser(String email, String password) {
AccountUser__c us=new AccountUser__c();
us.Email__c=email;
us.Password__c=password;
us.Status__c=0;
insert us;
return us.Id;
}
But result return is error:
[{"errorCode":"UNSUPPORTED_MEDIA_TYPE","message":"Content-Type header specified in HTTP request is not supported: application/x-www-form-urlencoded"}]
I had try change application/json to application/x-www-form-urlencoded , but still can't resolve.
I try call a Get method, it is ok.
Why Post method occur error [Content-Type header specified in HTTP request is not supported]?
I would like to suggest a better resolution. Retrofit Library
Even though it is not mandatory to use Retrofit, these are few eye catchy aspects which makes it reliable and handy in similar use case of yours.
Why to use Retrofit?
Type-safe REST Adapter that makes common networking tasks easy
For POST operations, retrofit helps in assembling what needed to be submitted. Eg:- Generating URL encoded form.
Takes care of URL manipulation, requesting, loading, caching, threading, synchronization, sync/async calls
Helps to generate URL using type-aware generated code tied to specific REST API
Parsing JSON using GSON
Retrofit is an API adapter wrapped over OkHttp
The problem that you are facing can be resolved using retrofit like this.
public interface APIConfiguration{
#Headers({"Accept:application/json",
"Content-Type:application/x-www-form-urlencoded"})
#FormUrlEncoded
#POST("user/registration")
Observable<DataPojo> registrationAPI(#FieldMap(encoded = true) Map<String, String> params);
}
That's it, with few annotation the library takes care of Form URL
Encoding and related dependencies.
As it is inappropriate to start from corresponding Retrofit dependencies and sample code, you can go through Reference One and Reference Two for more details.
As per my understanding just checkout the difference the content type header "application/x-www-form-urlencoded" is inefficient for sending large quantities of binary data or text containing non-ASCII characters. The content type "multipart/form-data" should be used for submitting forms that contain files, non-ASCII data, and binary data.
The content "multipart/form-data" follows the rules of all multipart MIME data streams.
https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4
Also try your http request by setting your content type header as multipart/formdata.

Retrofit2/OkHttp3: REST webservice does not specify characterset

I am accessing a webservice that are not able to specify content-type nor character set for the content I consume.
Is there a way, using retrofit2 (or okhttp3 client interceptors), to add information about this so that received content can be processed correctly?
With Retrofit you can use the #Headers annotation:
For instance:
#Headers("Cache-Control: max-age=640000")
You could then (if you always know the Content Type) set your Interface to be:
#Headers("Content-Type: application/json")
#GET("widget/list")
Call<List<Widget>> widgetList();
https://square.github.io/retrofit/

POST body JSON using Retrofit

I'm trying to POST a JSONObject using the Retrofit library, but when I see the request at the receiving end, the content-length is 0.
In the RestService interface:
#Headers({
"Content-type: application/json"
})
#POST("/api/v1/user/controller")
void registerController(
#Body JSONObject registrationBundle,
#Header("x-company-device-token") String companyDeviceToken,
#Header("x-company-device-guid") String companyDeviceGuid,
Callback<JSONObject> cb);
And it gets called with,
mRestService.registerController(
registrationBundle,
mApplication.mSession.getCredentials().getDeviceToken(),
mApplication.mSession.getCredentials().getDeviceGuid(),
new Callback<JSONObject>() {
// ...
}
)
And I'm certain that the registrationBundle, which is a JSONObject isn't null or empty (the other fields are certainly fine). At the moment the request is made, it logs out as: {"zip":19312,"useAccountZip":false,"controllerName":"mine","registrationCode":"GLD94Q"}.
On the receiving end of the request, I see that the request has Content-type: application/json but has Content-length: 0.
Is there any reason why sending JSON in the body like this isn't working? Am I missing something simple in using Retrofit?
By default, you don't need to set any headers if you want a JSON request body. Whenever you test Retrofit code, I recommend setting .setLogLevel(RestAdapter.LogLevel.FULL) on your instance of RestAdapter. This will show you the full request headers and body as well as the full response headers and body.
What's occurring is that you are setting the Content-type twice. Then you're passing a JSONObject, which is being passed through the GsonConverter and mangled to look like {"nameValuePairs":YOURJSONSTRING} where YOURJSONSTRING contains your complete, intended JSON output. For obvious reasons, this won't work well with most REST APIs.
You should skip messing with the Content-type header which is already being set to JSON with UTF-8 by default. Also, don't pass a JSONObject to GSON. Pass a Java object for GSON to convert.
Try this if you're using callbacks:
#POST("/api/v1/user/controller")
void registerController(
#Body MyBundleObject registrationBundle,
#Header("x-company-device-token") String companyDeviceToken,
#Header("x-company-device-guid") String companyDeviceGuid,
Callback<ResponseObject> cb);
I haven't tested this exact syntax.
Synchronous example:
#POST("/api/v1/user/controller")
ResponseObject registerController(
#Body MyBundleObject registrationBundle,
#Header("x-company-device-token") String companyDeviceToken,
#Header("x-company-device-guid") String companyDeviceGuid);

Categories

Resources