I'm trying to send a json post request to some API which in response sends a binary file back.
I'm doing well in Postman:
Header:
Body and result:
And I get the following code from Code section in Postman for Java/OKHTTP
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\r\n \"Text\":\"Hello\",\r\n \"APIKey\":\"MY_API_KEY\",\r\n \"Speaker\":\"Female1\",\r\n \"Format\":\"mp3/32/m\",\r\n \"Quality\":\"quality/normal\"\r\n}");
Request request = new Request.Builder()
.url("http://url/CloudService/ReadText")
.post(body)
.addHeader("content-type", "application/json")
.addHeader("cache-control", "no-cache")
.addHeader("postman-token", "0a1ce7c9-7a95-a2b9-7cde-8a7e6ce58386")
.build();
Response response = client.newCall(request).execute();
But when I use the above code in android it fails, I'm sure that I got Internet permission and the code is executed within an AsyncTask.
I'm not asking about the API or how to send json Post request to some API and get a binary file in response. I've used client.newCall(request).enqueue(new Callback(){//stuff here}); but none works. In response I got a 307 status code (instead of 200 in Postman) and no binary data at all. The API is very unclear and said nothing about the failure and I'm still working on that.
All I'm asking is that does Postman generates equivalent code for OkHttp correctly? and if not what is your suggestion for equivalent of this request in Java/OkHttp?
Just to provide another example, the following is also a working Python requests script to do the same job:
url = 'http://url/CloudService/ReadText'
api_key = 'MY_API_KEY'
body = {
'Text': 'Hello',
'Speaker': 'Female1',
'Format': 'mp3/32/m',
'Quality': 'quality/normal',
'APIKey': api_key
}
header = {
'Content-type': 'application/json'
}
r = requests.post(url, data=json.dumps(body), headers=header)
So after 3 days I found the problem, the server API did not mention that the URL endpoint must be ended with an / and even in their sample code they didn't use one.
It seems that both Postman and Python requests use an / at the end of URL in case of need, but Postman at least does not mention that in the generated equivalent code. Also OkHttp does not operate in the same manner.
However using a trailing / solved the problem.
Related
I am trying to process Http GET request with parameters using Okhttp in Android Kotlin.
As there is no GET resource found on documentation and other internet resources didn't work, how can I set GET request in Okhttp with pre defined parameters.
Builder code with lack of GET method
val parameter = "{\"phone\": \"$phone\"}"
val request = Request.Builder().url(weburl)
.header("User-Agent", "OkHttp Headers.java")
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
//.method("GET",parameter.toRequestBody())
.build()
Output result
enter image description here
If you want to send the phone as a query parameter, you should add it to the request URL, not to the request body. You don't need to specify the method: GET is the default. By the way, you can get rid of the Content-type header (GET requests, usually, have no content):
val url = weburl.toHttpUrl().newBuilder()
.addQueryParameter("phone", phone)
.build()
val request = Request.Builder().url(url)
.header("User-Agent", "OkHttp Headers.java")
.header("Accept", "application/json")
.build()
If your requirement is to send a GET request with a request body, than you are out of luck I'm afraid: OkHttp does not support it. Anyways, most likely, it's not what you want (unless you are calling Elasticsearch API...)
I have a DJANGO REST server on my personal network that is set up to get and receive JSON strings to update "statuses" for a project I'm working on. I can GET the information down into my Android application just fine but when I try to PUT information up to the server, I get the error:
Bad Request: /api/users/1/
[28/Oct/2019 21:23:23] "PUT /api/users/1/ HTTP/1.1" 400 107
I think it's the app because I can successfully do a PUT request via Windows Powershell, but it doesn't work on the Android app. Here is the code using the OKHTTP class:
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
String content = String.format("{'status':%s}", selectedStatus);
RequestBody body = RequestBody.create(JSON, content);
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(IPAddress + "api/users/" + currentUserID + "/")
.addHeader("Content-Type", "application/json")
.put(body) //PUT
.build();
client.newCall(request).execute();
I have tried using the standard HttpURLConnection class, which is what I did for the GET method, but I don't even get a response from the server when I do that. I've tried about a dozen ways to PUT something to the server, but nothing has worked. Any help achieving this goal would be appreciated. Thanks.
For anyone looking at this later, I found the issue. It turns out that in the Windows Powershell, you can use single quotes in the JSON string, but you NEED to use double quotes with the OKHTTP methods. Thus, I changed:
String content = String.format("{'status':%s}", selectedStatus);
to:
String content = String.format("{\"status\":%s}", selectedStatus);
and everything went through perfectly. Hope this helps someone.
I am using an API that is out of my control, as well having joined a development team recently that is using Retrofit1.
I am unable to send the request to the server in the format required, as the server requires multipart form data Body in the following format:
Uniqueidentifier:FileName.jpg:ReroutServerIP:Base64EncodedDocString.
I have tried many different techniques in order to accomplish this task but I cannot find any working method to do this. The server tells me that the message format not supported. Here is my current code (with the url stripped out). Please could someone assist?
#POST("URL")
public Response post_SendData(#Header("Content-Type") String ContentType, #Body String body);
In order to achieve the desired result, I can use postman with no headers and post a file from my system using the form-data post method. In the working postman post, the Key is the formatted string mentioned above and the value is a file selected from my desktop. Please see below for postman (edited to remove urls).
Postman
Thanks a lot guys.
If you want to send a file to the server :
public void uploadPictureRetrofit(File file, Callback<YourObject> response) {
// this will build full path of API url where we want to send data.
RestAdapter restAdapter = new RestAdapter
.Builder()
.setEndpoint(YOUR_BASE_URL)
.setConverter(new SimpleXMLConverter()) // if the response is an xml
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
// SubmitAPI is name of our interface which will send data to server.
SendMediaApiInterface api = restAdapter.
create(SendMediaApiInterface.class);
TypedFile typedFile = new TypedFile(MULTIPART_FORM_DATA, file);
api.sendImage(typedFile, response);
}
And this is the interface SendMediaApiInterface :
public interface SendMediaApiInterface {
#Multipart
#POST("url")
void sendImage(#Part("here_is_the_attribute_name_in_webservice") TypedFile attachments, Callback<YourObject> response);}
When posting the same basic JSON from Android or via curling, the result is different.
I'm trying to understand why? I'm assuming there is something about Rails that I don't understand.
Command Line HTTP POST
curl 'http://localhost:3000/mobile/register' -X POST -H 'Content-Type:
application/json' -d '{"user": {"email": "awesome#example.com",
"password":"helloworld", "password_confirmation":"helloworld"}}'
Server logs
Parameters: {"user"=>{"email"=>"awesome#example.com",
"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"},
"registration"=>{"user"=>{"email"=>"awesome#example.com",
"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}}}
Android HTTP POST
OkHttpClient client = new OkHttpClient();
JSONObject userObject = new JSONObject();
userObject.put("email", mUserEmail);
userObject.put("password", mUserPassword);
userObject.put("password_confirmation", mUserPasswordConfirmation);
String userString = userObject.toString();
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("user", userString)
.build();
Request request = new Request.Builder()
.url(REGISTER_API_ENDPOINT_URL)
.method("POST", RequestBody.create(null, new byte[0]))
.post(requestBody)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback()...
Server logs
Parameters:
{"user"=>"{\"email\":\"awesome#example.com\",\"password\":\"helloworld\",\"password_confirmation\":\"helloworld\"}"}
Rails Routes:
devise_scope :user do
namespace :mobile do
post '/register', to: 'registrations#create', as: :register
end
end
Differences:
curling hides the password but Android does not
curling adds an additional nested JSON with all the data repeated
I'm not sure what causes these differences?
UPDATE
I checked request.env["CONTENT_TYPE"] in the controller action and I am seeing differences in Content-Type.
Curl -> application/json
Android -> multipart/form-data; boundary=...
Could this cause the issue?
Is it easy to change from the Android side? I added .header("Content-Type", "application/json") to the request but it makes no difference?
I think the Android HTTP POST lacks the Content-Type: application/json header because it sends multipart form data . So the rails app logs it as plain string data instead of parsing it, registering user and filtering password.
Also, in case of curl command, the parsed JSON user object is used to register a user. The repeated log entry is perhaps done during this user registration.
To make both requests equivalent, try using the POST TO A SERVER example given at http://square.github.io/okhttp/.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am having an issue in my app, I need to be able to see or log the full network request so that I can see exactly what parameters are being posted to my server with what headers, currently it only shows me the URL, is there a way of doing this in android studio or is there some code I can write to display this data?
To further explain things seems the terms network request, parameters and headers are confusing people, I use the google volley library for all my htpp requests; GET, POST, PUT etc. Now when posting data to a URL or getting data via a specific URL i need to be able to confirm that the right parameters and headers are being sent to the server.
If you are talking about testing the parameters for your API, you probably looking for REST clients like:
Postman
Rest Client
to validate services. But before that, you should have proper documentation of all the web services.
Solution:
In Android Studio, to debug your code, simply place breakpoints on the code and press debug button to execute
You can place breakpoint by clicking on left of each line where breakpoint is shown.
Also check this tutorial:
Simple Debugging in Android Studio and follow further videos for proper debugging.
I would recommend you to use OkHttp for making all network calls. OkHttp provides Interceptors which will serve your exact purpose.
Defining an interceptor:
class LoggingInterceptor implements Interceptor {
#Override public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
logger.info(String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers()));
HttpUrl url = request.url(); // url of the request.
Headers reqHeaders = request.headers(); // Here you are able to access headers which are being sent with the request.
RequestBody body = request.body(); // provides body of request, which you can inspect to see what is being sent.
Response response = chain.proceed(request);
long t2 = System.nanoTime();
logger.info(String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));
Headers resHeaders = response.headers(); // Headers received in the response.
return response;
}
}
Using it to make network calls:
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.build();
Request request = new Request.Builder()
.url("http://www.publicobject.com/helloworld.txt")
.header("User-Agent", "OkHttp Example")
.build();
Response response = client.newCall(request).execute();
response.body().close();
Explore the Interceptors for more customization.