Retrofit response body returning null - kotlin

I've been stuck with this problem for some time now, and I can't seem to find the problem especially when all I did was following a guide online.
I'm trying to make a POST request, and receive a response in exchange:
Request body:
{
"Email":"test#gmail.com",
"firebaseUid":"Test_UID",
"IsBanned":1
}
Response body:
`
{
"Email": "test#gmail.com",
"UserId": 7
}
So basically whenever I submit a request to /users/ to create an account, I get both the email and UserId returned.
data class UserLogin(
#SerializedName("Email") val Email: String,
#SerializedName("UserId") val UserId: Int?,
#SerializedName("IsBanned") val IsBanned: Boolean?,
#SerializedName("firebaseUid") val firebaseUid: String?
)
object ServiceBuilder {
private val client = OkHttpClient.Builder().build()
private val retrofit = Retrofit.Builder()
.baseUrl("http://10.0.2.2/8000/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
fun<T> buildService(service: Class<T>): T{
return retrofit.create(service)
}
}
class RestApiService {
fun addUser(userData: UserLogin, onResult: (UserLogin?) -> Unit){
val retrofit = ServiceBuilder.buildService(RestApi::class.java)
retrofit.addUser(userData).enqueue(
object : Callback<UserLogin> {
override fun onFailure(call: Call<UserLogin>, t: Throwable) {
Log.d("Failed retrofit",t.message.toString())
onResult(null)
}
override fun onResponse( call: Call<UserLogin>, response: Response<UserLogin>) {
val addedUser = response.body()
onResult(addedUser)
}
}
)
}
}
onFailure doesn't seem to be printing anything on the console. I'm calling the API from a button like this and both Email and UserId keep returning null for some reason:
`
val apiService = RestApiService()
val userInfo = UserLogin(UserId = null,firebaseUid = "TestTestTest", IsBanned = false, Email = "test#gmail.com");
apiService.addUser(userInfo){
Log.d("Retrofit user added", it?.Email.toString())
}
`
I tried to:
Set default values for the data class members.
Tried to check if response is successfull, and then print the errorBody if not. That didn't help either. I'm getting unreadable errors like $1#9afe35d instead.
Everything seem to be working fine when I do requests manually with POSTMAN.

It turned out there was nothing with the code. I just typed the port the wrong way and used a / instead of :
private val retrofit = Retrofit.Builder()
.baseUrl("http://10.0.2.2:8000/") // this
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()

Related

How to use the information stored in mutableStateOf in Jetpack Compose

I have information in json and I retrieve it using retrofit2, everything works fine, I get the data in a List.
I need this information to fill elements in Jetpack Compose for which I use mutableStateOf to save the states.
My function that I use is the following:
fun jsonParsing(
dataRecox: MutableState<List<Event>>
) {
val TAG_LOGS = "Mariox"
val retrofit = Retrofit.Builder()
.baseUrl("http://myserversample.com/pGet/track/")
.addConverterFactory(GsonConverterFactory.create())
.build()
val retrofitAPI = retrofit.create(APIService1::class.java)
retrofitAPI.getRecolector().enqueue(object : Callback<List<Event>> {
override fun onResponse(
call: Call<List<Event>>,
response: Response<List<Event>>
) {
val data = response.body()
val mydata = data!!
dataRecox.value = mydata
Log.i(TAG_LOGS, Gson().toJson(data))
}
override fun onFailure(call: Call<List<Event>>, t: Throwable) {
t.printStackTrace()
}
})
}
Mymodel:
data class Event (
val deviceID : Int,
val statusCode : Int,
val accountID : String,
val speedKPH : Int,
.
.
.
}
My composable:
#Composable
fun Greeting(name: String) {
val dataRecox = remember {
mutableStateOf(emptyList<Event>())
}
jsonParsing(dataRecox)
println("======")
println(dataRecox) // ok data
println(dataRecox.value). // ok data
//Uncommenting println(dataRecox.value[0]) I get empty.
//println(dataRecox.value[0])
//Text(text = dataRecox.value[0].uniqueID)
}
When I do not use the information in the console, by calling Greeting("Android") all the data is printed correctly:
The problem comes when I want to use that information:
For example, if I want to print in console println(dataRecox.value[0]) here it returns empty. If I want to use it with a composable Text: Text(text = dataRecox.value[0].uniqueID) it also gives me empty.
Can someone explain to me why this happens, because when I start using the information the data becomes empty.
The way you're doing is totally different of the recommended way... here's my suggestion.
Define a class to represent the screen's state.
data class ScreenState(
val events: List<Event> = emptyList(),
val error: Throwable? = null
)
Use a ViewModel to perform the API request and keep the screen state.
class EventsViewModel : ViewModel()
private val _screenState = MutableStateFlow<ScreenState>(ScreenState())
val screenState = _screenState.asStateFlow()
init {
jsonParsing()
}
fun jsonParsing() {
val TAG_LOGS = "Mariox"
val retrofit = Retrofit.Builder()
.baseUrl("http://myserversample.com/pGet/track/")
.addConverterFactory(GsonConverterFactory.create())
.build()
val retrofitAPI = retrofit.create(APIService1::class.java)
retrofitAPI.getRecolector().enqueue(object : Callback<List<Event>> {
override fun onResponse(
call: Call<List<Event>>,
response: Response<List<Event>>
) {
val data = response.body()
Log.i(TAG_LOGS, Gson().toJson(data))
_screenState.update {
ScreenState(it.events)
}
}
override fun onFailure(call: Call<List<Event>>, t: Throwable) {
t.printStackTrace()
_screenState.update {
ScreenState(error = t)
}
}
})
}
}
Instantiate the ViewModel and use it in your screen...
#Composable
fun Greeting(name: String) {
val vm = viewModel<EventsViewModel>()
val screenState by vm.screenState.observeAsState()
LazyColumn(Modifier.fillMaxSize()) {
items(screenState.items) {
Text(it. accountID)
}
}
}

Retrofit response with internal error with code 500

trying to use post/put call method in my Kotlin frontend to get response from Django backend. Method Get works but if I use ResponseBody nothing happens and log gives error with code 500.
Can someone help me?
This is my Api interface, where PUT and POST method doesnt work
public interface Api {
#GET("api/users")
fun getUsers(): Call<UserResults>
#PUT("/api/users/{Id}")
suspend fun updateUser(#Body requestBody: RequestBody, #Path("Id") userId: String): Response<ResponseBody>
#POST("/api/users")
suspend fun createUser(#Body requestBody: RequestBody): Response<ResponseBody>
}
This is function for example for PUT method
private fun updateSettings(preferredBranch: String) {
// Create Retrofit
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.build()
// Create Service
val service = retrofit.create(Api::class.java)
// Create JSON using JSONObject
val jsonObject = JSONObject()
jsonObject.put("preferred_branch", preferredBranch)
//jsonObject.put("job", "iOS Developer")
// Convert JSONObject to String
val jsonObjectString = jsonObject.toString()
// Create RequestBody ( We're not using any converter, like GsonConverter, MoshiConverter e.t.c, that's why we use RequestBody )
val requestBody = jsonObjectString.toRequestBody("application/json".toMediaTypeOrNull())
CoroutineScope(Dispatchers.IO).launch {
// Do the PUT request and get response
val response = service.updateUser(requestBody, logId.toString())
withContext(Dispatchers.Main) {
if (response.isSuccessful) {
// Convert raw JSON to pretty JSON using GSON library
val gson = GsonBuilder().setPrettyPrinting().create()
val prettyJson = gson.toJson(
JsonParser.parseString(
response.body()
?.string() // About this thread blocking annotation : https://github.com/square/retrofit/issues/3255
)
)
Log.d("Pretty Printed JSON :", "test")
} else {
Log.e("RETROFIT_ERROR", response.code().toString())
}
}
}
}

What is the parameter for request and response body okhttp in kotlin

I start to code the app in kotlin with okhttp3. I get response body but how I can get the info that I need? For example, I use Google example. I just want to get the "name:". How I can tell my request that I what get only "name:"? Can you help with some code example or some source with instruction and description about OkHTTP? I read official documentation but didn't find something or just didn't understand.
fun run(url: String){
val request = Request.Builder().url(url).build()
//client.authenticator()
val client = OkHttpClient()
.newBuilder()
.addInterceptor { chain ->
val originalRequest = chain.request()
val builder = originalRequest
.newBuilder()
val name = request.header("name")
//.header("Authorization",
// Credentials.basic("login", "password"))
val newRequest = builder.build()
chain.proceed(newRequest)
}.build()
client.newCall(request).enqueue(object : Callback{
override fun onFailure(call: Call, e: IOException) {
toast("fail")
e.printStackTrace()
}
override fun onResponse(call: Call, response: Response) {
textView3.setText(response.body()?.string())
}
})
I tried to use .header("name") but it was red and I think I make some mistake.
Thank for every suggestions
Here is a way to do it with Jackson ObjectMapper
as per your example, let's say you receive the following content in the response:
{
"login": "defunkt",
"id": 2,
"name": "Chris Wanstrath",
"company": null,
"blog": "http://chriswanstrath.com/"
}
but you are only interested to in the name field, therefore you define a User class:
public class User { private String name; }
and then using the ObjectMapper configured to ignore the missing properties:
// content = response.body().string();
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
try {
User user = mapper.readValue(content, User.class);
System.out.println(user.getName()); // Chris Wanstrath
} catch (JsonProcessingException e) {
e.printStackTrace();
}

retrofit Give kotlin.KotlinNullPointerException

Data get from the Sql server and get data json. this json data parsing retofit2.
Created Login Activity but its give error
MainActivity.kt
class MainActivity : AppCompatActivity() {
internal lateinit var api : APIInterface
private var compositeDisposable : CompositeDisposable? = null
var userName : String? = null
var password : String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnLogin.setOnClickListener {
userName = tvUsername.text.toString()
password = tvPassword.text.toString()
getUserName(userName!!,password!!)
}
}
fun getUserName(user : String, pass : String){
val retrofit = APIClient.apIClient
if (retrofit != null) {
api = retrofit.create(APIInterface::class.java)
}
compositeDisposable!!.add(api.getLoginData(user, pass)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
if (it.success.equals(1)){
val intent = Intent(this,Company::class.java)
startActivity(intent)
Toast.makeText(this,"Login Successfully!!!",Toast.LENGTH_LONG).show()
}else{
Toast.makeText(this,"UserName or Password is Wrong!!!",Toast.LENGTH_LONG).show()
}
},{
Toast.makeText(this, it.message, Toast.LENGTH_LONG).show()
})
)
}
}
when Debbuger reached on compositeDisposable!!.add(api.getLoginData(user, pass) it's give Error kotlin.kotlinNullPointerException
RestApi Url :
http://localhost/Account/Login.php?user=ABC&pass=1
APIClient.kt
object APIClient {
val BASE_URL = "http://10.0.2.2/Account/"
var retrofit:Retrofit? = null
val apIClient:Retrofit?
get() {
if (retrofit == null)
{
retrofit = Retrofit.Builder().
baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
}
return retrofit
}
}
APIInterface.kt
interface APIInterface {
#GET("Login.php")
fun getLoginData(#Query("user") user : String,
#Query("pass") pass : String) : Observable<LoginList>
}
The most likely cause for the NullPointerException is that compositeDisposable is null.
At the beginning of MyActivity that variable is initialised to null and then it's never changed, so when you use the !! operator the exception is thrown.
I think you can initialise compositeDisposable directly with the correct value, i.e. something like val compositeDisposable = CompositeDisposable().
Also, val should be preferred over var whenever possible – as immutability is easier to control – and userName and password could probably be local variable or at least private

Retrofit 2 Get Github Users API always returning null

I tried to get json from the https://github.com/users.
I want to show username : yehezkiell like https://github.com/yehezkiell.
The retrofit showing success result, but its always return null. I'm new in this retrofit, please help
this my code
val postService = DataRepository.create()
postService.getUser("yehezkiell").enqueue(object : Callback<Users>{
override fun onFailure(call: Call<Users>?, t: Throwable?) {
Log.e("retrofitnya","gagal ${t}")
}
override fun onResponse(call: Call<Users>?, response: Response<Users>?) {
Log.e("retrofitnya","berhasil")
val data = response?.body()
Log.e("retrofitnya","berhasil ${data?.name}")
}
})
Retrofit Instance
interface RetrofitInstance {
#GET("users/{username}")
fun getUser(#Path("username") username:String ): Call<Users>
}
Data repo
object DataRepository {
fun create(): RetrofitInstance {
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://github.com")
.build()
return retrofit.create(RetrofitInstance::class.java)
}
}
Users.kt
open class Users {
#SerializedName("name")
#Expose
open var name: String? = null
#SerializedName("username")
#Expose
open var username: String? = null
#SerializedName("email")
#Expose
open var email: String? = null
}
For debugging process, instead of de-serialization to Users object immediately after response, should we do somethings like these? :
De-serialize it to plain string first.
interface RetrofitInstance {
#GET("users/{username}")
fun getUser(#Path("username") username: String): Call<String>
}
Just log that string to show what we really get.
override fun onResponse(call: Call<String>?, response: Response<String>?) {
val responseBody = response?.body() ?: ""
Log.e("retrofitnya","response body as string = ${responseBody}")
}
(If we want to use it as Users after that) do manually de-serialize it.
val user: Users = Gson().fromJson(responseBody, Users::class.java)
If it is not too confidential, plz give us how you declare that Users data object like, for example, this Foo and Bar.
data class Foo(
#SerializedName("bar") val bar: Bar?
)
data class Bar(
#SerializedName("name") val name: String?
)
I solved this by myself, actually its my silly miss understanding which is that end point is wrong.
In my wrong code
object DataRepository {
fun create(): RetrofitInstance {
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://github.com")
.build()
return retrofit.create(RetrofitInstance::class.java)
}
}
That wrong end point is
https://github.com
The true one is
https://api.github.com/