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.
Related
I am using Retrofit v2.4.0 in my project. I need to get token using one API call and using this token in header of the POST request I should use another API call where I should add one header and two parameter to the body of the request. The following code is of the second API call (JavaRx is used):
#FormUrlEncoded
#POST("auth/sendCode")
#Headers("Content-Type: application/json")
Single<SendCodeResponse> sendCode(#Header("token") String token,
#Field("phoneNumber") String phoneNumber,
#Field("langCode") String langCode);
However, it is not working. When I log my request, it is showing that the request body is not correct.
What is wrong with my code above?
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.
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);
I am using Retrofit/Robospice to make api calls in an app I've built, with a RetrofitGsonSpiceService. All responses are converted into POJOs using a GSON converter, however there is some information I need to retrieve from the response header. I cannot find any means to get the headers (I can only get the headers if the request is unsuccessful because the raw response is sent in the error object!) how can I intercept the response to grab the headers before it is converted?
It took me a few minutes to figure out exactly what #mato was suggesting in his answer. Here's a concrete example of how to replace the OkClient that comes with Retrofit in order to intercept the response headers.
public class InterceptingOkClient extends OkClient
{
public InterceptingOkClient()
{
}
public InterceptingOkClient(OkHttpClient client)
{
super(client);
}
#Override
public Response execute(Request request) throws IOException
{
Response response = super.execute(request);
for (Header header : response.getHeaders())
{
// do something with header
}
return response;
}
}
You then pass an instance of your custom client to the RestAdapter.Builder:
RestAdapter restAdapter = new RestAdapter.Builder()
.setClient(new InterceptingOkClient())
....
.build();
RoboSpice was designed in a way it doesn't know anything about the HTTP client you end up using in your app. That being said, you should get the response headers from the HTTP client. As Retrofit may use Apache, OkHttp or the default Android HTTP client, you should take a look and see which client you are currently using. Take into account that Retrofit chooses the HTTP client based on certain things (please refer to the Retrofit documentation, or dig into the code, you will find it), unless you manually specify it.
Retrofit defines an interface for clients called Client. If you take a look at the source code, you will see that three classes implement this interface: ApacheClient, OkClient and UrlConnectionClient. Depending on which of them you want to use, extend from one of those, and try to hook into the code that is executed when a response comes back, so that you can get the headers from it.
Once you do that, you have to set your custom Client to 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);