API ๋ฌธ์์์ Response๊ฐ์ด string..
Media type์ด image/png ์ผ ๋..
์ด๋ป๊ฒ ํ์๋์..?
๋๋ถ๊ณ ๋ฐฑํ์๋ฉด,, ๊ทธ๋์ json ์๋ต๊ฐ๋ง ์ฒ๋ฆฌํ์ด์ string๋ง? ๋ ์ฉ? ๐ฎ
์ด์ง ๊ฐ์ด ์์์ postman๊น์ง ๋๋ ค๋ดค๋๋ฐ ๋ฆฌ์ผ๋ฃจ ์ด๋ฏธ์ง ํ์ผ์ด ์จ๊ฑฐ ๋ณด๊ณ
๋๋ฌผ์ ์ฝ์ง์ ํ์ต๋๋ค..
๊ฐ๋ฐ ํ๊ฒฝ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- Retrofit2 2.9.0
- okhttp3 4.11.0
์๋ (json ์๋ต๊ฐ)๋ผ๋ฉด,
@POST("transform")
suspend fun request(
@Part("type") type: RequestBody,
@Part img: MultipartBody.Part,
): Response<String>
Response<String> ๊ฐ์ผ๋ก ๋ฐ์์ → apicall ๋ฐ๋ ๋ถ๋ถ์์ json์ผ๋ก ๋ง๋ค์ด → ResultData๋ก ๋๊ฒจ์ฃผ๋ ์์ ์ ๊ฑฐ์น๋ ์ฝ๋๋ก ์์ ํ์์ต๋๋ค.
suspend inline fun <reified T : Any> apiCall(
call: suspend () -> Response<String>
): ResultData<T> {
suspend inline fun apiCall(
call: suspend () -> Response<ResponseBody>,
): ResultData<T> {
return try {
val json = Json {
encodeDefaults = true
prettyPrint = true
isLenient = true
ignoreUnknownKeys = true
coerceInputValues = true
}
val response = call.invoke()
val responseStr = response.body() ?: ""
if (response.isSuccessful) {
ResultData.Success(json.decodeFromString<T>(responseStr))
} else {
ResultData.Error(errorMessage = response.errorBody()?.toString() ?: " api response error")
}
(๋จธ ์ด๋ฐ์์ผ๋ก…)
๊ทธ๋ฆฌ๊ณ ResultData๋ฅผ ๋ฐ๋ DataSourceImpl ๊ฐ์ ๋ถ๋ถ์์๋ ์ง์ ์์ฑํ data class๋ก ๋งคํํ์์ฃ …
( ๋ฐฉ๋ฒ์ ์ฌ๋ฌ๊ฐ์ง๊ฒ ์ง๋ง์ ๐ )
๊ทธ๋ฐ๋ฐ ์ด๊ฒ ์๊พธ ์๋ฌ๊ฐ ๋๋๊ฒ๋๋ค..?
JSON document was not fully consumed
kotlinx.serialization.json.internal.JsonDecodingException: Expected start of the object ‘{‘, but had ‘EOF’ instead
๊ทธ๋์ ๋ค์ api ๋ฌธ์๋ฅผ ์ฐพ์๋ณด๊ณ .. ๋ด๋น ๊ฐ๋ฐ์๋ถ์ด ์ฌ๋ ค์ฃผ์ ์์๋ ๋ค์ ์ฝ์ด๋ณด๋
'response๋ฅผ image binary๋ก ๋๋ฆฝ๋๋ค' ์๋ ๊ฒ์ ๋๋ค..!!
๊ฒฐ๋ก ๋ถํฐ ์ ์ด๋ณด์๋ฉด
๋จผ์ Retrofit ์ค์ ์ ์๋ต๊ฐ์ ๋ง๋ ConvertFactory ๋ฑ๋ก์ ํด์ผํฉ๋๋ค.
๋ฐ์์ค๋ ๊ฐ์ด json์ด ์๋ ๋ฌธ์์ด์ด๊ธฐ ๋๋ฌธ์
GsonConverterFactory๊ฐ ์๋ ScalarsConverterFactory๋ฅผ ์ฌ์ฉํ๋๊ฒ ๋ง๋๋ผ๊ตฌ์.
@Provides
@Singleton
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.client(okHttpClient)
.build()
}
๊ทธ๋ฆฌ๊ณ ResponseBody๋ก ๋ฐ์ byteArray๋ก ๋ณํํ๋ฉด ๋๋ ๊ฒ์ด์์ต๋๋ค..
@POST("transform")
suspend fun request(
@Part("type") type: RequestBody,
@Part img: MultipartBody.Part,
): Response<ResponseBody>
์ด๋ ๊ฒ ResponseBody๋ก ๋ฐ๋ ์ด์ ๋ ๋ด์ฅํจ์๋ก bytes()๊ฐ ์๊ธฐ ๋๋ฌธ์ธ๋ฐ์,,
์ ๋ bytes() ์ด์ฉํ๋ ค๊ณ ResponseBody ๋ก ๋ฐ์๊ฑฐ๋๊น ๊ผญ ์ด๋ ๊ฒ ์ํด๋ ๋ ๊ฒ ๊ฐ์ต๋๋ค
suspend inline fun apiCall(
call: suspend () -> Response<ResponseBody>,
): ResultData<ByteArray?> {
return try {
val response = call.invoke()
if (response.isSuccessful) {
ResultData.Success(response.body()?.bytes())
} else {
ResultData.Error(errorMessage = response.errorBody()?.toString() ?: "response error")
}
} catch (e: Exception) {
Log.e("API CALL","${e.cause} \n${e.message}")
ResultData.Error(errorMessage = e.message)
}
}
response.body()๋ฅผ ๋ฐ๋ก bytes() ๋ก ๋ฐ๊ฟ ResultData<ByteArray> ๋ฅผ ๋ฐํํ๊ณ
viewModel์์ Bitmap์ผ๋ก ๋ฐ๊พธ๋ฉด
val bitmap = BitmapFactory.decodeByteArray(data.image, 0, data.image?.size?:0)
jetpack compose ๊ธฐ์ค!
Image(
bitmap = data.asImageBitmap(),
contentDescription = "",
modifier = Modifier
.fillMaxWidth()
)
์ด๋ ๊ฒ ์ด๋ฏธ์ง๋ฅผ ๋์ธ ์ ์๋ ๊ฒ์ ๋๋ค!
์ด ๊ณผ์ ์ด ์กฐ๊ธ ํ๋ค์๋๊ฒ
binary string์ด๋ผ ๋ก๊ทธ ์ถ๋ ฅ๋ ์ ์๋๊ณ
์๋๋ก์ด๋๋ก ๋์ธ ์ ์๋ ์ด๋ฏธ์ง๋ก ๋ณํํ๋ ๊ณผ์ ์์ ์๊พธ null๋ง ๋ฐํํ๊ธฐ์
์ ๊ธฐ์ค ์กฐ๊ธ ๊น๋ค๋ก์ ์ต๋๋ค..
์๋ต๊ฐ์ผ๋ก id๊ฐ์ด๋ผ๋๊ฐ.. createdTime์ด๋ผ๋๊ฐ… ์ ํ ์๊ณ ์ค๋ก์ง ์ด๋ฏธ์ง ํ์ผ๋ฟ์ด๋ผ๋ฉด!
์ฐธ๊ณ ๊ฐ ๋์์ผ๋ฉด ์ข๊ฒ ์ต๋๋ค..
๐๐ปโ๏ธ