2
votes

I just started learning kotlin and my first app use Retrofit2 and Coroutine, but there is problem. I have some error, but by Coroutine the stack trace is very poor in informations. Maybe someone will find a mistake or knows hot to make the stack trace more informative.

ApiService:

const val API_KEY = "Bcae2032bb596c73b10bdab625c037da"

interface CurrencyApi {

//https://api.currencystack.io/currency?base=USD&target=EUR&apikey=Bcae2032bb596c73b10bdab625c037da

@GET("currency")
fun getCurrentCurrency(
    @Query("base") base: String,
    @Query("target") target: String
): Deferred<Currency>

companion object {
    operator fun invoke(): CurrencyApi {
        val requestInterceptor = Interceptor { chain ->

            val url = chain.request()
                .url()
                .newBuilder()
                .addQueryParameter("key", API_KEY)
                .build()
            val request = chain.request()
                .newBuilder()
                .url(url)
                .build()

            return@Interceptor chain.proceed(request)
        }

        val okHttpClient = OkHttpClient.Builder()
            .addInterceptor(requestInterceptor)
            .build()

        return Retrofit.Builder()
            .client(okHttpClient)
            .baseUrl("https://api.currencystack.io/")
            .addCallAdapterFactory(CoroutineCallAdapterFactory())
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(CurrencyApi::class.java)
    }
}

Activity:

 class MainActivity : AppCompatActivity(), AdapterView.OnItemSelectedListener {


override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    val model = ViewModelProviders.of(this).get(MainViewModel::class.java)

    val apiService = CurrencyApi()

    GlobalScope.launch(Dispatchers.Main) {
        val currency = apiService.getCurrentCurrency("PLN", "EUR").await()
        return@launch try {
            text_view_test.text = currency.toString()
        } catch (e: Exception) {

        }
    }

Logcat:

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.daniellachacz.currencyconverter, PID: 10924 retrofit2.HttpException: HTTP 400 at com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory$BodyCallAdapter$adapt$2.onResponse(CoroutineCallAdapterFactory.kt:104) at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:123) at okhttp3.RealCall$AsyncCall.execute(RealCall.java:153) at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) at java.lang.Thread.run(Thread.java:818)

3

3 Answers

5
votes

You receive server error 400 Bad Request response. This status code indicates that the server could not understand the request due to invalid syntax. Try to debug or put some logs and see what you are really sending to the server. I think the good place to debug is in the implementation of Interceptor interface.

0
votes

As @Sergey said, it is a server error.

In my case it couldn't be caught by an API and the server wrote: An internal server error occurred. (code 500) instead of a JSON.

0
votes

Replace @GET(currency) to @GET(currency.json)