0

I am trying to call an API using Retrofit in an Android application using Kotlin. The API requires a a header and body similar to the following sample input:

Sample Input

Header:

loginName: 65848614-6697-4cf7-a64a-e0b9374c4aee

Body:

clientId: DKOKTrykIQ987yQcLNehT8SWJRMyQLdP secret: 6Jt1ENlDn9gxPu5f

The content type has to be passed as application/x-www-form-urlencoded.

Currently, I am using the following classes:

YodleeService.kt

interface YodleeService {

        @Headers(
            "loginName: de5559cc-5375-4aca-8224-990343774c08_ADMIN",
            "Api-Version: 1.1",
            "Content-Type: application/x-www-form-urlencoded"
        )
        @POST("auth/token")
        fun generateLoginToken(
            @Body postBody: PostBody
        ) : Call<LoginToken>
}

AccountRetriever.kt

class AccountRetriever {
    private val service: YodleeService

    companion object {
        const val BASE_URL = "https://sandbox.api.yodlee.com:443/ysl/"
    }

    init {
        val retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()

        service = retrofit.create(YodleeService::class.java)
    }

    fun login(callback: Callback<LoginToken>) {
        val postBody = PostBody("TG86ljAk6lt28GYZlRTQWssaLmGpS6jV", "A2P9ZPEqB4uos1nv")
        val call = service.generateLoginToken(postBody)
        call.enqueue(callback)
    }
}

PostBody

data class PostBody(
    val clientId: String?,
    val secret: String?
)

MainActivity

class MainActivity : AppCompatActivity() {

    private val accountRetriever = AccountRetriever()

    private val loginCallback = object : Callback<LoginToken> {
        override fun onFailure(call: Call<LoginToken>, t: Throwable) {
            Log.e("MainActivity", "Problem calling Yodlee API {${t.message}")
        }

        override fun onResponse(call: Call<LoginToken>?, response: Response<LoginToken>?) {
            response?.isSuccessful.let {
                Log.i("MainActivity", "errorBody - Content = ${response?.raw()}")
                val loginToken = LoginToken(
                    response?.body()?.accessToken ?: "",
                    response?.body()?.expiresIn ?: "",
                response?.body()?.issuedAt ?: "")
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        accountsList.layoutManager = LinearLayoutManager(this)

        if (isNetworkConnected()) {
            accountRetriever.login(loginCallback)
        } else {
            AlertDialog.Builder(this).setTitle("No Internet Connection")
                .setMessage("Please check your internet connection and try again")
                .setPositiveButton(android.R.string.ok) { _, _ -> }
                .setIcon(android.R.drawable.ic_dialog_alert).show()
        }
    }

    private fun isNetworkConnected(): Boolean {
        val connectivityManager =
            getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val activeNetwork = connectivityManager.activeNetwork
        val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork)
        return networkCapabilities != null &&
                networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    }
}

When I debug my application, I am getting a response of [size=213 text=\n {\n "errorCode": "Y303",\n …]. The documentation for the API says that this error code means the clientId or secret is missing.

When I dig through the debugger, I am seeing that the raw call reads as

Request {
    method = POST, url = https: //sandbox.api.yodlee.com/ysl/auth/token, 
        tags = {
            class retrofit2.Invocation =
            com.example.budgettracker.api.YodleeService.generateLoginToken()[PostBody(
                clientId = TG86ljAk6lt28GYZlRTQWssaLmGpS6jV, secret = A2P9ZPEqB4uos1nv)]
        }
}

I cannot determine why the API is not seeing the POST body contents. Any help would be greatly appreciated.

Mark Scheer
  • 117
  • 2
  • 6
  • when i tried i get following error `com.ds.retrofit2 E/MainActivity: Problem calling Yodlee API {socket failed: EPERM (Operation not permitted)` can you give me access? – ruben Oct 28 '20 at 23:03
  • I recreated the situation with your error. Delete the app from your emulator and re-run the app. That should get rid of the error. https://stackoverflow.com/questions/56266801/java-net-socketexception-socket-failed-eperm-operation-not-permitted – Mark Scheer Oct 29 '20 at 00:25
  • ok after doing so i get this error message `errorBody - Content = Response{protocol=http/1.1, code=400, message=Bad Request, url=https://sandbox.api.yodlee.com/ysl/auth/token}` maybe need new clientid and token – ruben Oct 30 '20 at 20:35

0 Answers0