I am using Square Retrofit version 2.0 beta2. I have tried to follow this tutorial .I am trying to upload a bitmap image to the server but somehow code is not working. I have tried testing my server using postman and I am able to post photo and even able to retrieve it. Here is my flask controller.
#app.route('/api/photo/user/<int:user_id>', methods=["POST"])
def post_user_photo(user_id):
app.logger.info("post_user_photo=> user_id:{}, photo: {}".format(
user_id,
request.files['photo'].filename,
))
user = User.query.get_or_404(user_id)
try:
user.photo = request.files['photo'].read()
except Exception as e:
app.logger.exception(e)
db.session.rollback()
raise
db.session.commit()
return "", codes.no_content
I have used the postman to test my controller and here is the request generated by postman.
POST /api/photo/user/5 HTTP/1.1
Host: blooming-cliffs-9672.herokuapp.com
Cache-Control: no-cache
Postman-Token: 8117fb79-4781-449d-7d22-237c49b53389
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="photo"; filename="sfsu.jpg"
Content-Type: image/jpeg
----WebKitFormBoundary7MA4YWxkTrZu0gW
I have defined the retrofit service and the to upload the image and here is my Android code. Interface part
#Multipart
#POST("/api/photo/user/{userId}")
Call<Void> uploadUserProfilePhoto(#Path("userId") Integer userId, #Part("photo") RequestBody photo);
Here client builder part
public static BeamItService getService(){
if (service == null) {
OkHttpClient client = new OkHttpClient();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
HttpLoggingInterceptor interceptor2 = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
client.interceptors().add(interceptor);
client.interceptors().add(interceptor2);
service = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build().create(BeamItService.class);
}
return service;
}
And here is the Android activity code which tries to upload the bitmap.
private void uploadProfilePhoto(){
BeamItService service = BeamItServiceTransport.getService();
MediaType MEDIA_TYPE_PNG = MediaType.parse("image/jpeg");
byte [] data = BitmapUtility.getBitmapToBytes(((BitmapDrawable) ivProfilePhoto.getDrawable()).getBitmap());
Log.d(TAG, String.format("Profile detals => user_id: %d, size of data: %d", 5, data.length));
RequestBody requestBody1 = RequestBody.create(MEDIA_TYPE_PNG,
data);
Log.d(TAG, "requestBody: " + requestBody1.toString());
RequestBody requestBody2 = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addPart(Headers.of("Content-Disposition", "form-data; name=\"photo\"; filename=\"t.jpg\""),
requestBody1)
.build();
Log.d(TAG, "requestBody: " + requestBody2.toString());
// ProfileDetails profileDetails = new DBHelper(this).fetchProfileDetails();
Call<Void> call = service.uploadUserProfilePhoto(5, requestBody2);
call.enqueue(new ProfilePhotoUploadCallback());
}
private class ProfilePhotoUploadCallback implements Callback<Void> {
#Override
public void onResponse(Response<Void> response, Retrofit retrofit) {
Log.d(TAG, String.format("ProfilePhotoUploadCallback=> code: %d", response.code()));
}
#Override
public void onFailure(Throwable t) {
}
}
But it fails to upload it, flask app returns status code 400 every time. I tried to put the breakpoint in the flask app, but request doesn't even reach there.
here is the server log
2015-11-02T06:05:42.288574+00:00 heroku[router]: at=info method=POST path="/api/photo/user/5" host=blooming-cliffs-9672.herokuapp.com request_id=2cc8b6c8-f12a-4e4b-8279-cedfc39712f2 fwd="204.28.113.240" dyno=web.1 connect=1ms service=88ms status=400 bytes=347
2015-11-02T06:05:42.209347+00:00 app[web.1]: [2015-11-02 06:05:42 +0000] [11] [DEBUG] POST /api/photo/user/5
I also tried to enable the retrofit intercepter and log the request and response, but I don't get the entire POST request body. Here is the Android log.
11-02 00:24:22.119 3904-4382/com.contactsharing.beamit D/OkHttp: --> POST /api/photo/user/5 HTTP/1.1
11-02 00:24:22.119 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Type: multipart/form-data; boundary=4031e177-0e4b-4f16-abe8-20c54e506846
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Length: 17171
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Host: blooming-cliffs-9672.herokuapp.com
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Connection: Keep-Alive
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: Accept-Encoding: gzip
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: User-Agent: okhttp/2.6.0-SNAPSHOT
11-02 00:24:22.120 3904-4382/com.contactsharing.beamit D/OkHttp: --> END POST
11-02 00:24:22.179 3904-4537/com.contactsharing.beamit I/DBHelper: Updated row: 1
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: <-- HTTP/1.1 400 BAD REQUEST (195ms)
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Connection: keep-alive
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Server: gunicorn/19.3.0
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Date: Mon, 02 Nov 2015 08:24:22 GMT
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Type: text/html
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Content-Length: 192
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: Via: 1.1 vegur
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: OkHttp-Selected-Protocol: http/1.1
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: OkHttp-Sent-Millis: 1446452662120
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: OkHttp-Received-Millis: 1446452662316
11-02 00:24:22.316 3904-4382/com.contactsharing.beamit D/OkHttp: <-- END HTTP
Please help, I am stuck and not able to make any progress.
You are nesting a multipart request body here (A multipart within a multipart).
Implemented something similar recently, instead of using #Multipart and #Part you can use #Body with MultipartBuilder.
#POST("/api/photo/user/{userId}")
Call<Void> uploadUserProfilePhoto(#Path("userId") Integer userId, #Body RequestBody photo);
Then instead of using MultipartBuilder.addPart(...) use MultipartBuilder.addFormDataPart(name, filename, requestBody)
private void uploadProfilePhoto() {
BeamItService service = BeamItServiceTransport.getService();
MediaType MEDIA_TYPE_PNG = MediaType.parse("image/jpeg");
byte [] data = BitmapUtility.getBitmapToBytes(((BitmapDrawable) ivProfilePhoto.getDrawable()).getBitmap());
Log.d(TAG, String.format("Profile detals => user_id: %d, size of data: %d", 5, data.length));
RequestBody requestBody1 = RequestBody.create(MEDIA_TYPE_PNG, data);
Log.d(TAG, "requestBody: " + requestBody1.toString());
RequestBody requestBody2 = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addFormDataPart("photo", "t.jpg", requestBody1)
.build();
Log.d(TAG, "requestBody: " + requestBody2.toString());
// ProfileDetails profileDetails = new DBHelper(this).fetchProfileDetails();
Call<Void> call = service.uploadUserProfilePhoto(5, requestBody2);
call.enqueue(new ProfilePhotoUploadCallback());
}
Related
I have a problem with retrofit 2. I'm sending some data to Microsoft EAS server but a response is received after 20 sec. Why I know that this is a retrofit problem? Because without retrofit it is working correctly.
my logs:
D/OkHttp: --> POST https://{my_host}/Microsoft-Server-ActiveSync?Cmd=Provision&User={myuser}&DeviceId=837bc6c5690b40b98ab55f7a2231e50c&DeviceType={mydevicetype} http/1.1
D/OkHttp: Content-Type: application/vnd.ms-sync.wbxml
D/OkHttp: Content-Length: 456
D/OkHttp: Authorization: Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
D/OkHttp: MS-ASProtocolVersion: 14.1
D/OkHttp: Connection: keep-alive
D/OkHttp: User-Agent: MyUserAgent
D/OkHttp: X-MS-PolicyKey: 0
D/OkHttp: [3,1,106,0,0,14,[...more here...],88,77,76,0,1,1,1,1] // <--- body
D/OkHttp: --> END POST (456-byte body)
after 20 sec (it seems like I receive response after 20 + normal receive time - in this case: 20596ms):
D/OkHttp: <-- 200 OK https://{my_host}/Microsoft-Server-ActiveSync?Cmd=Provision&User={myuser}&DeviceId=837bc6c5690b40b98ab55f7a2231e50c&DeviceType={mydevicetype} (20596ms)
D/OkHttp: Content-Type: application/vnd.ms-sync.wbxml
D/OkHttp: request-id: {request_id}
D/OkHttp: Set-Cookie: {cookie_data}
D/OkHttp: X-CalculatedBETarget: {target}.local
D/OkHttp: X-MS-BackOffDuration: L/-470
D/OkHttp: X-DiagInfo: EXCHANGEHA
D/OkHttp: X-BEServer: EXCHANGEHA
D/OkHttp: Set-Cookie: {cookie_data}
D/OkHttp: X-FEServer: EX01
D/OkHttp: Date: Fri, 07 Oct 2016 10:30:08 GMT
D/OkHttp: <-- END HTTP (binary 15-byte body omitted)
If I'm requesting it without retrofit, it sends me response immiedetaly.
My code:
Init:
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(chain -> {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.addHeader("Authorization", getAuth(account))
.addHeader("MS-ASProtocolVersion", getProtocolVersion())
.addHeader("Connection", getConnectionType())
.addHeader("User-Agent", getUserAgent())
.addHeader("X-MS-PolicyKey", getPolicyKey());
Request request = requestBuilder.build();
return chain.proceed(request);
});
if (EasConfig.isDebug()) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient.addInterceptor(logging);
}
httpClient.readTimeout(30, TimeUnit.SECONDS);
httpClient.writeTimeout(30, TimeUnit.SECONDS);
OkHttpClient client = httpClient.build();
retrofit = new Retrofit.Builder()
.baseUrl(getBaseUrl(account))
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
Call:
ActiveSyncService service = retrofit.create(ActiveSyncService.class);
service.getData(getContentType(), command, getUser(account), getDeviceId(), getUserAgent(), serializer.toByteArray());
Endpoint:
#POST("Microsoft-Server-ActiveSync")
Call<ResponseBody> getData(#Header("Content-Type") String contentType, // <--- it has to be here -- it's not woking if I set it in incerteptor (don't know why)
#Query("Cmd") String command,
#Query("User") String user,
#Query("DeviceId") String deviceId,
#Query("DeviceType") String deviceType,
#Body byte[] data);
My POST request keeps sending as GET & got rejected by API endpoint
MyService class
#FormUrlEncoded
#POST("api/users/")
Call<List<User>> getUsers(#FieldMap HashMap<String, String> parameters);
Request code
Gson builder = new GsonBuilder().setLenient().create();
Retrofit client = new Retrofit.Builder()
.baseUrl(Constants.API_ENDPOINT_TEST_URL)
.addConverterFactory(GsonConverterFactory.create(builder))
.build();
mApiService = client.create(MyService.class);
Call<List<User>> call = mApiService.getUsers(mParameters);
call.enqueue(new Callback<List<User>>() {
#Override
public void onResponse(Call<List<User>> call, Response<List<User>> response) {
mResponse = response.body();
mResponseObserver.onFinish(mResponse);
}
#Override
public void onFailure(Call<List<User>> call, Throwable t) {
mResponseObserver.onFailure();
}
});
But server rejects it as it reached the server in GET request form !? Having checked with debugger, I saw that:
rawResponse.request.method = GET
Here is screenshot of watch window showing the retrofit's request object:
As you can see, the request method was GET. But the weird part is in the tag, it shows a request object with POST method?
Am i miss something here?
UPDATE
I added logging interceptor & here is the log:
D/OkHttp: --> POST http://***/api/users/ http/1.1
D/OkHttp: Content-Type: application/x-www-form-urlencoded
D/OkHttp: Content-Length: 56
D/OkHttp: --> END POST
D/OkHttp: <-- 200 OK https://***/api/users/ (388ms)
D/OkHttp: Date: Thu, 01 Sep 2016 11:50:23 GMT
D/OkHttp: Server: Apache
D/OkHttp: X-Powered-By: PHP/5.4.34
D/OkHttp: Cache-Control: max-age=2592000
D/OkHttp: Expires: Sat, 01 Oct 2016 11:50:23 GMT
D/OkHttp: Vary: Accept-Encoding
D/OkHttp: Content-Type: application/json; charset=UTF-8
D/OkHttp: Set-Cookie: SESSION_DEFAULT=***; expires=Sun, 04-Sep-2016 11:50:24 GMT; path=/; HttpOnly
D/OkHttp: Set-Cookie: COOKIE[***]=***; path=/; httponly
D/OkHttp: Connection: close
D/OkHttp: <-- END HTTP
looks like the request is a POST. But, the server still responds with error message, saying that the request method is a GET
Hmm, I'll dig a little bit more into it.
Actually, the issue is the combination of 2 factors:
Wrong request protocol has been made (http instead of https)
Server responded with a weird message on wrong protocol: "GET is not supported".
ANyway, thanks #nshmura for your assistant.
I checked your program with logging, and confirms the POST request is sent.
I recommend you to check like this:
class TestClass {
private void testRequest() {
HashMap<String, String> mParameters = new HashMap<>();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(logging); // <-- this is the important line!
Gson builder = new GsonBuilder().setLenient().create();
Retrofit client = new Retrofit.Builder()
.baseUrl(Constants.API_ENDPOINT_TEST_URL)
.addConverterFactory(GsonConverterFactory.create(builder))
.client(httpClient.build())
.build();
MyService mApiService = client.create(MyService.class);
Call<List<User>> call = mApiService.getUsers(mParameters);
call.enqueue(new Callback<List<User>>() {
#Override
public void onResponse(Call<List<User>> call, Response<List<User>> response) {
}
#Override
public void onFailure(Call<List<User>> call, Throwable t) {
}
});
}
interface MyService {
#FormUrlEncoded
#POST("api/users/")
Call<List<User>> getUsers(#FieldMap HashMap<String, String> parameters);
}
class User {
}
class Constants {
public static final String API_ENDPOINT_TEST_URL = "http://.........";
}
}
here is request log:
D/OkHttp: --> POST http://......... http/1.1
D/OkHttp: Content-Type: application/x-www-form-urlencoded
D/OkHttp: Content-Length: 0
D/OkHttp: --> END POST
Here is response:
D/OkHttp: <-- 200 OK http://.............../ (167ms)
D/OkHttp: Server: nginx
D/OkHttp: Date: Thu, 01 Sep 2016 11:30:32 GMT
D/OkHttp: Content-Type: text/html; charset=UTF-8
D/OkHttp: Connection: close
....
D/OkHttp: <-- END HTTP
I met a similar problem. In my case, I received in response to 301, redirect and change of method POST -> GET.
First, check your BASE_URL, it must be of the form "h ttps://www.YourSite.com/" www - very important. If everything is in place and the problem still exists, then you can change as described below:
From okhttp wiki and based on this image, you need to change something like this:
...
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
final RequestBody requestBody = new FormBody.Builder().build();
httpClient.addNetworkInterceptor(new Interceptor() {
#Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl.Builder builder = request.url().newBuilder();
HttpUrl url = builder.build();
request = request.newBuilder()
.url(url)
.post(requestBody)
.build();
return chain.proceed(request);
}
})
httpClient.addInterceptor(logging);
...
Can u try
#POST("/api/users/")
With slash before "api"?
Also it would be helpful to double check request with Fiddler or smth.
That is partly correct a http client behavior. According to the HTTP spec
If the 307 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.
Sometime it is not possible to change backend API. So here a workaround you can add to you interceptor to manually redirect a request with correct method.
fun forceRedirectMethod(chain: Interceptor.Chain, originResponse: Response): Response {
/* TODO
one more request is made; disable followRedirect and make it manually?
*/
if (originResponse.priorResponse()?.code() == 302) {
val priorResponse: Response = originResponse.priorResponse() as Response
val redirectRequest = priorResponse.request()
val builder = originResponse.request().newBuilder()
.method(redirectRequest.method(), redirectRequest.body())
val newRequest = builder.build()
return chain.proceed(newRequest)
} else {
return originResponse
}
}
I'm trying to send a .wav file using Retrofit2 on Android in order to use the Create Enrollment request of the Microsoft Speaker Recognition API (https://dev.projectoxford.ai/docs/services/563309b6778daf02acc0a508/operations/56406930e597ed20c8d8549c)
But I always get the following Error 400:
com.mobile.cir.voicerecognition D/OkHttp: <-- 400 Bad Request https://api.projectoxford.ai/spid/v1.0/verificationProfiles/94BC205B-FACD-42A7-9D80-485403106627/enroll (3907ms)
com.mobile.cir.voicerecognition D/OkHttp: Cache-Control: no-cache
com.mobile.cir.voicerecognition D/OkHttp: Pragma: no-cache
com.mobile.cir.voicerecognition D/OkHttp: Content-Length: 123
com.mobile.cir.voicerecognition D/OkHttp: Content-Type: application/json; charset=utf-8
com.mobile.cir.voicerecognition D/OkHttp: Expires: -1
com.mobile.cir.voicerecognition D/OkHttp: X-AspNet-Version: 4.0.30319
com.mobile.cir.voicerecognition D/OkHttp: X-Powered-By: ASP.NET
com.mobile.cir.voicerecognition D/OkHttp: apim-request-id: e5472946-ec90-4662-a3c9-dda62c2c6b27
com.mobile.cir.voicerecognition D/OkHttp: Date: Fri, 12 Aug 2016 11:43:04 GMT
com.mobile.cir.voicerecognition D/OkHttp: }
com.mobile.cir.voicerecognition D/OkHttp: <-- END HTTP (123-byte body)
com.mobile.cir.voicerecognition D/EnableVoiceRecognition: Upload success
com.mobile.cir.voicerecognition D/errorĀ message: RequestError{code='null', message='null'}
Here is my Apiclient class:
public static Retrofit getClient() {
if (retrofit==null) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient httpClient = new OkHttpClient.Builder().addInterceptor(logging).build();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient)
.build();
}
return retrofit;
}
The POST request:
#Multipart
#POST("verificationProfiles/{VerificationProfileId}/enroll")
Call<EnrollmentResponse> createEnrollment(#Path("VerificationProfileId") String profileId,
#Header("Content-Type") String contentType,
#Header("Ocp-Apim-Subscription-Key") String subscriptionKey,
#Part("file") RequestBody audioFile);
}
And the action itself:
File audioFile = new File(fileDirectory + "my_voice.wav");
RequestBody requestAudioFile = RequestBody.create(MediaType.parse("application/octet-stream"), audioFile);
Call<EnrollmentResponse> call = apiService.createEnrollment(PROFILE_ID_TEST,"audio/wav; samplerate=1600",API_KEY,requestAudioFile);
call.enqueue(new Callback<EnrollmentResponse>() {
#Override
public void onResponse(Call<EnrollmentResponse> call, Response<EnrollmentResponse> response) {
Log.d(TAG,"Upload success");
RequestError error = ErrorUtils.parseError(response);
Log.d("error message", error.toString());
Log.d(TAG,"Response: " + response.body().toString());
}
#Override
public void onFailure(Call<EnrollmentResponse> call, Throwable t) {
Log.d(TAG,"Upload error: " + t.getMessage());
}
});
Where am I doing wrong?
* EDIT *
Microsoft developers released the Android library for this API
(https://github.com/Microsoft/Cognitive-SpeakerRecognition-Android)
I'm sure this is a non issue for someone who knows what they're doing, but this is my first time using MailChimp's api and retrofit. Basically, my api key is always missing. I have no idea what MailChimp's proper url looks like when you are including an api key.
The url I am attempting is:
/3.0/lists/613cd953b2/members?user=email#gmail.com:apikey
And others of that variety
http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#create-post_lists_list_id_members
curl --request GET \
--url 'https://.api.mailchimp.com/3.0/' \
--user 'anystring:your_apikey'
This says GET but I am attempting a post.
Here is my android / java code...
final OkHttpClient client = new OkHttpClient();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
client.interceptors().add(interceptor);
client.interceptors().add(new Interceptor() {
#Override
public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
// .header("Authorization", basic)
.header("user", "email#gmail.com:apikey");
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
//Create interface instance
MailChimpAPI apiService = retrofit.create(MailChimpAPI.class);
Email chimpEmail = new Email("hi#hi.hi");
Call<Email> call = apiService.addUser(chimpEmail);
call.enqueue(new Callback<Email>() {
#Override
public void onResponse(Response<Email> response, Retrofit retrofit) {
int statusCode = response.code();
//Log.d("tag", "enter the void");
Log.d("tag", statusCode + "");
Log.d("tag", client.toString());
}
#Override
public void onFailure(Throwable t) {
Log.d("tag", t.toString());
}
});
And how I define my interface method
#POST("/3.0/lists/613cd953b2/members")
Call<Email> addUser(#Body Email email);
And my retrofit log...
D/OkHttp: --> POST /3.0/lists/613cd953b2/members HTTP/1.1
D/OkHttp: {"email_address":"hi#hi.hi","merge_fields":{"FNAME":"","LNAME":""},"status":""}
D/OkHttp: --> END POST (79-byte body)
D/OkHttp: <-- HTTP/1.1 401 (299ms)
D/OkHttp: OkHttp-Selected-Protocol: h2
D/OkHttp: server: nginx
D/OkHttp: content-type: application/problem+json; charset=utf-8
D/OkHttp: x-request-id: 6b6ca6a9-c141-45fc-8de7-ec0922892bbf
D/OkHttp: link: <https://us12.api.mailchimp.com/schema/3.0/ProblemDetailDocument.json>; rel="describedBy"
D/OkHttp: vary: Accept-Encoding
D/OkHttp: date: Tue, 05 Jan 2016 21:21:45 GMT
D/OkHttp: set-cookie: _AVESTA_ENVIRONMENT=prod; path=/
D/OkHttp: OkHttp-Sent-Millis: 1452028904738
D/OkHttp: OkHttp-Received-Millis: 1452028904830
D/OkHttp: {"type":"http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/","title":"API Key Missing","status":401,"detail":"Your request did not include an API key.","instance":""}
D/OkHttp: <-- END HTTP (193-byte body)
I was not using basic authentication properly. I followed this tutorial
https://futurestud.io/blog/android-basic-authentication-with-retrofit
and it fixed my error! Yay for new errors!
Also for future people, maybe this might help you.
BASIC AUTHORIZATION isn't just a way to describe something! It's an actual concept and implementable! haha
What the title says. The problem only happens when using Retrofit. Uploads using Postman or Android's HTTPURLConnection+DataOutputStream work fine and return the json body from the REST api.
Here's a working request/response log from Postman:
Remote Address: xxx.xxx.xxx.xxx:80 Request URL: [ --- secret --- ]
Request Method:POST Status Code:200 OK Response Headers (8) Request
Headers view source Accept:*/* Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8,pt;q=0.6,gl;q=0.4
Cache-Control:no-cache Connection:keep-alive Content-Length:11519
Content-Type:multipart/form-data;
boundary=----WebKitFormBoundaryGlChAAe9WOKlPy2D
Cookie:laravel_session= [...] Host: [secret]
Request Payload
------WebKitFormBoundaryGlChAAe9WOKlPy2D Content-Disposition: form-data; name="upload[]"; filename="avatar.png" Content-Type:
image/png
------WebKitFormBoundaryGlChAAe9WOKlPy2D--
Here's the Retrofit version:
----> HTTP POST http://xxxxxxx
Accept: application/json
Content-Type: multipart/form-data
Content-Length: 9094
--1d87e0b7-bf5d-4034-b20b-48155a5dee2a
Content-Disposition: form-data; name="upload[]" filename="picSuggestion.jpg"
Content-Type: image/jpeg Content-Length: 8846
Content-Transfer-Encoding: binary
---> END HTTP (9094-byte body)
<--- HTTP 200 http://xxxxxxxx/api/uploads/?api=true&token=xxxx(1240ms)
: HTTP/1.1 200 OK
Cache-Control: no-cache
Connection: keep-alive
Content-Type: text/html; charset=UTF-8
Date: Fri, 28 Aug 2015 13:11:20 GMT
Server: nginx/1.4.6 (Ubuntu)
Set-Cookie: laravel_session=xxxxxxx; path=/; httponly
Transfer-Encoding: chunked
X-Android-Received-Millis: 1440767479264
X-Android-Response-Source: NETWORK 200
X-Android-Sent-Millis: 1440767478578
X-Powered-By: PHP/5.5.9-1ubuntu4.11
<--- END HTTP (0-byte body)
We tried a bunch of Retrofit service and interceptor configurations without success, but here's the latest one we tried
requestInterceptor2 = new RequestInterceptor() {
#Override
public void intercept(RequestInterceptor.RequestFacade request) {
request.addHeader("Content-Type", "multipart/form-data" );
request.addHeader("Accept", "application/json" );
request.addQueryParam("key", API_KEY);
}
};
#Multipart
#POST("/api/uploads/")
void uploadImage(#Part(value = "upload[]", encoding = "binary") TypedFile payload, #Query("api") boolean api, #Query("token") String token, Callback<uploadImagePoiResultVO> cb);