I'd like to set MIME type to "application/x-msgpack" but the type of MultipartBody should be MediaType so the app crashs.
How do I make a request?
val media = "multipart/form-data".toMediaTypeOrNull()
val boundary = System.currentTimeMillis().toString()
val file = MoshiPack().jsonToMsgpack("sample_file").readByteArray()
val requestBody: RequestBody = MultipartBody.Builder(boundary).setType("application/x-msgpack".toMediaTypeOrNull()!!)
.addFormDataPart("file", "fileName", file.toRequestBody(media, 0, file.size))
.build()
val request = Request.Builder()
.header("Content-Type", "application/json; charset=utf-8;multipart/form-data")
.url(requestUrl)
.post(paramData)
.post(requestBody)
.build()
okHttpClient.newCall(request)
implementation "com.squareup.okhttp3:okhttp:4.6.0"
You should only call post once per request you are building. Leave out the header("Content-Type", ...) call as it conflicts as well.
See https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/PostMultipart.java
So something like
var requestBody: RequestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(
"file", "fileName",
file.toRequestBody("application/x-msgpack".toMediaType())
)
.build()
var request: Request = Request.Builder()
.header("Authorization", "Client-ID XXXX")
.url("https://api.imgur.com/3/image")
.post(requestBody)
.build()
Related
I need to upload audio file with binary body with retrofit like the image bellow in postman:
how can i upload audio file with binary body like the image with retrofit?
This is what I did but its not work:
#Multipart
#POST("upload")
fun uploadAudio(
#Part audio_file: MultipartBody.Part
): Call<ModelGetAudioUrl>
And this is how I prepare audio file for multipartbody.Part:
According to your screenshot, you propably don't want to use a multipart body. So something like
#POST("upload")
fun uploadAudio(#Body audio_file: TypedInput): Call<ModelGetAudioUrl>
or #Body audio_file: RequestBody should work (see How to send byte[] array in retrofit).
I solve it by using okhttp:
val client = OkHttpClient().newBuilder()
.callTimeout(90, TimeUnit.SECONDS)
.readTimeout(90, TimeUnit.SECONDS)
.connectTimeout(90, TimeUnit.SECONDS)
.writeTimeout(90, TimeUnit.SECONDS)
.build();
val mediaType = "audio/wave".toMediaTypeOrNull();
val body = RequestBody.create(mediaType, soundFile)
val request = Request.Builder()
.url("https://api.assemblyai.com/v2/upload")
.method("POST", body)
.addHeader("authorization", "99fa2a59e27e4688b9f7edcdc8ed7185")
.addHeader("Transfer-Encoding", "chunked")
.addHeader("Content-Type", "audio/wave")
.build()
Thread {
try {
val response = client.newCall(request).execute().use {
if (it.isSuccessful) {
val str = it.body?.string()
if (!str.isNullOrEmpty()) {
val json = JSONObject(str)
sendUrlToTranscript(json.getString("upload_url"))
}
}
context.runOnUiThread {
if (!it.isSuccessful) {
loading.hideDialog()
}
}
}
}catch (e: Exception) {
e.printStackTrace()
Log.d("uploadAudio", "uploadAudio: ${e.message}")
}
}.start()
I have an api call with basic auth, multiple headers and request body. But my request is not working with retrofit. So just to verify I checked with okhttp and it is working.
Below is my retrofit code
Api Interface
#POST("login")
suspend fun login(#HeaderMap headers:HashMap<String,String>, #Body body: RequestBody): retrofit2.Response<Any>
Retrofit Instance
#Singleton
#Provides
fun injectRetrofitAPI() : ApiInterface {
val logging = HttpLoggingInterceptor()
logging.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder()
.addInterceptor(logging)
.build()
return Retrofit.Builder().client(client)
.addConverterFactory(MoshiConverterFactory.create())
.baseUrl(AppConstants.BASE_URL).build().create(ApiInterface::class.java)
}
This is how I am creating my headers and body
private fun createParameters() {
headers["db"] = "P"
headers["latitud"] = "0"
headers["longitud"] = "0"
headers["apiKey"] = "a9f1b3fd3d5a62782f24d2d00afe4532"
headers["Content-Type"] = "application/json"
val credentials = String.format("%s:%s", "centro", "Salud1011.")
val auth = "Basic " + Base64.encodeToString(credentials.toByteArray(), Base64.NO_WRAP)
headers["Authorization"] = auth
body = MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("usuario", binding.etUsername.text.toString())
.addFormDataPart("password", binding.etPwd.text.toString())
.build()
Log.d("okhttp", "createParameters: ")
}
And I am simply calling it like this
viewModel.login(body, headers)
Api is giving response but it is going in failure case. I am suspecting that body parameters are not being sent in request as in error it is saying related to username and password.
Below is the OkHttp code which works
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("usuario","FELIPEG")
.addFormDataPart("password","Fel10**11$$")
.build();
Request request = new Request.Builder()
.url("http://200.6.231.237:11000/gasolinera/v1/login")
.method("POST", body)
.addHeader("db", "P")
.addHeader("latitud", "0")
.addHeader("longitud", "0")
.addHeader("apiKey", "a9f1b3fd3d5a62782f24d2d00afe4532")
.addHeader("Authorization", "Basic Y2VudHJvOlNhbHVkMTAxMS4=")
.addHeader("Content-Type", "application/json")
.build();
Response response = client.newCall(request).execute();
I can't find the exact issue with retrofit.
I need to get "status" value from my response. I tried JSONObject but it gave that java.lang.reflect.InvocationTargetException error in the code below. I need that because I make some process with status value like start new activity etc. How can I get this?
private fun doReq(){
val client = OkHttpClient().newBuilder()
.build()
val mediaType = "application/json;charset=utf-8".toMediaTypeOrNull()
val body: RequestBody = jsonSended.toRequestBody(mediaType)
val request: Request = Request.Builder()
.url("https://apiapiapi/auth")
.method("POST", body)
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "$authValue")
.addHeader("x-iyzi-rnd", "$randomString")
.addHeader("cache-control", "no-cache")
.build()
val response = client.newCall(request).execute()
println(response.body?.string()) // I CAN GET RESPONSE BODY
var json = JSONObject(response.body.toString())
var status = json.getString("status") // HERE NOT WORKING...
println(status)
}
In the response when server return failure : {"status":"failure","errorCode":"12","errorMessage":"invalid","locale":"tr","systemTime":1610022545347,"conversationId":"123412341234"}
If server return valid my response is very very long but it also have status so I can get that status value and do something with that. Is that correct way to do it? I need advice.
Use response.response or make request in try catch block statement, it will solve the problem
Something like this
private fun doReq(){
try {
var errorResponce: ErrorResponce? = null
val client = OkHttpClient().newBuilder()
.build()
val mediaType = "application/json;charset=utf-8".toMediaTypeOrNull()
val body: RequestBody = jsonSended.toRequestBody(mediaType)
val request: Request = Request.Builder()
.url("https://apiapiapi/auth")
.method("POST", body)
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "$authValue")
.addHeader("x-iyzi-rnd", "$randomString")
.addHeader("cache-control", "no-cache")
.build()
val response = client.newCall(request).execute()
println(response.body?.string()) // I CAN GET RESPONSE BODY
if (response.errorBody() != null) {
errorResponce = conversorDeErro.convert(response.errorBody()!!)
}
}
catch (e: IOException) {
println(e);
}
finally {
return errorResponce;
}
}
You should read response.body?.string() exactly once and store the result.
val response = client.newCall(request).execute()
println(response.body?.string()) // This permanently consumes the output, you should store the result
var json = JSONObject(response.body.toString()) // toString() is not the response body, it is a debug representation of the response body
var status = json.getString("status")
I'm using Okio to download a file....with my request i'm sending some parameters, but since I wasn't getting my file and I was able to log my request and this is what is see:
Why tags is null? that means that the parameters are null
Request: Request{method=POST, url=https://mywesite.com/, tag=null}
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("user", "test")
.addFormDataPart("pass", "1234")
.build();
Request request = new Request.Builder()
.url(imageLink)
.post(requestBody)
.build();
Here is example:
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
from: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/guide/PostExample.java
Inside my Android kotlin app i'm calling some apis by using retrofit2 like
#FormUrlEncoded
#POST("something/some")
fun callMyApi(
#Field("myField") myField: String
): Deferred<MyResponseClass>
Now i need to add some common post params to all my api request (and keep the specific ones for each call, in this case i need to keep "myField"), so i'm using an interceptor:
val requestInterceptor = Interceptor { chain ->
val newRequest = chain.request()
.newBuilder()
.post(
FormBody.Builder()
.add("common1Key", "common1")
.add("common2Key", "common2")
.add("common3Key", "common3")
.build()
)
.build()
return#Interceptor chain.proceed(newRequest)
}
But this implementation fails because the interceptor seems to overwrite myField.
How can i fix it?
We can create Interceptor by using two or more common query parameter.
val requestInterceptor = Interceptor { chain ->
val url = chain.request()
.url()
.newBuilder()
.addQueryParameter("common1key", "common1")
.addQueryParameter("common2key", "common2")
.addQueryParameter("common3key", "common3")
.build()
val request = chain.request()
.newBuilder()
.url(url)
.build()
return#Interceptor chain.proceed(request)
}
I have added Interceptor for post form body.
interface PostWebApiService {
#POST("posts")
#FormUrlEncoded
fun savePost(
#Field("title") title: String
): Deferred<Post>
companion object {
operator fun invoke(): PostWebApiService {
val requestInterceptor = Interceptor { chain ->
var request = chain.request()
val requestBuilder = request.newBuilder()
val formBody = FormBody.Builder()
.add("body", "Body")
.add("userId", "12")
.build()
var postBodyString = bodyToString(request.body())
val concat = if (postBodyString.isNotEmpty()) "&" else ""
postBodyString = postBodyString + concat + bodyToString(formBody)
request = requestBuilder.post(
RequestBody.create(
MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"),
postBodyString
)
)
.build()
return#Interceptor chain.proceed(request)
}
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(requestInterceptor)
.build()
return Retrofit.Builder()
.client(okHttpClient)
.baseUrl("http://jsonplaceholder.typicode.com/")
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(PostWebApiService::class.java)
}
fun bodyToString(request: RequestBody?): String {
try {
var buffer = Buffer()
request?.writeTo(buffer)
return buffer.readUtf8()
} catch (e: IOException) {
return "error"
}
}
}
}