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()
Related
I am attempting to make a sync call that needs to complete before proceeding with storing a user in the cloud. I believe the issue is within the RequestBody as it looks like it is just a byte array. Below is the code:
val client = OkHttpClient()
val mediaType: MediaType? = "application/json".toMediaTypeOrNull()
val body: RequestBody =
RequestBody.create(mediaType, "{\"type\":\"DEFAULT\",\"name\":\"lkjlkj\"}")
val request: Request = okhttp3.Request.Builder()
.url("https://api.example.com/endpoint")
.post(body)
.addHeader("Accept", "application/json")
.addHeader("Content-Type", "application/json")
.addHeader(
"Authorization",
"Bearer SK-xxxxxx-4QAXH"
)
.build()
Toast.makeText(this#RegisterActivity, "Entering Call",Toast.LENGTH_SHORT).show()
val response: Unit = client.newCall(request).execute().use {
Toast.makeText(this#RegisterActivity, "sent call, awaiting response",Toast.LENGTH_SHORT).show()
if (it.isSuccessful){
val content = JSONObject(it.body.toString())
desiredString = content.getJSONArray("desiredStringField").toString()
Toast.makeText(this#RegisterActivity, desiredString,Toast.LENGTH_SHORT).show()
}
if (!it.isSuccessful){
Toast.makeText(this#RegisterActivity, "failed",Toast.LENGTH_SHORT).show()
}
}
The code doesn't crash but it seems the call never completes, as it never makes it into the it.isSuccessful or !it.isSuccessful. Perhaps its a bad formed call somehow. Please help if you can.
Try to enqueue the request and manage the response using a Callback:
client.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
if (!response.isSuccessful){
Toast.makeText(this#RegisterActivity, "failed",Toast.LENGTH_SHORT).show()
return
}
try {
val content = JSONObject(response.body?.string() ?: "")
desiredString = content.getJSONArray("desiredStringField").toString()
Toast.makeText(this#RegisterActivity, desiredString,Toast.LENGTH_SHORT).show()
} catch (e: JSONException) {
// Error parsing JSON object
}
}
override fun onFailure(call: Call, e: IOException) {
Toast.makeText(this#RegisterActivity, "failed",Toast.LENGTH_SHORT).show()
}
}
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'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()
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"
}
}
}
}
I am using retrofit2 in kotlin, and I need to get the content that is a json and this encrypted, I know that to convert json just use the JacksonConverterFactory (until this part was working well) but an encryption was added before that and I do not know how To handle this, do I need to create a converter of my own? Does anyone have a read to tell me?
My current call for retrofit
val retrofit = Retrofit.Builder()
.baseUrl("http://100.1.1.100/")
.addConverterFactory(JacksonConverterFactory.create())
.client(httpClient.build())
.build()
And i already have my fucntion (working) to decrypt:
CryptAES.decrypt(value))
This can be done by creating an decrypt interceptor:
class DecryptInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response = chain
.run { proceed(request()) }
.let { response ->
return#let if (response.isSuccessful) {
val body = response.body()!!
val contentType = body.contentType()
val charset = contentType?.charset() ?: Charset.defaultCharset()
val buffer = body.source().apply { request(Long.MAX_VALUE) }.buffer()
val bodyContent = buffer.clone().readString(charset)
response.newBuilder()
.body(ResponseBody.create(contentType, bodyContent.let(::decryptBody)))
.build()
} else response
}
private fun decryptBody(content: String): String {
//decryption
return content
}
}
setup:
val httpClient = OkHttpClient().newBuilder()
httpClient.addInterceptor(DecryptInterceptor())
val retrofit = Retrofit.Builder()
.baseUrl("http://100.1.1.100/")
.addConverterFactory(JacksonConverterFactory.create())
.client(httpClient.build())
.build()