I try to post data and get the response with POST using retrofit. In postman it works fine but in code it error.
this is the last thing I tried
service
#FormUrlEncoded
#POST("program/get/list-user-program")
fun getProgram(
#Field("comunity") comunity:String,
#Field("programGroupUrl") programGroupUrl:Int
): Call<ListProgramResponse>
activity
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(URL_BASE)
.addConverterFactory(GsonConverterFactory.create())
.build()
val apiService: Service = retrofit.create(Service::class.java)
val call: Call<ListProgramResponse> = apiService.getProgram("abc", 0)
call.enqueue(object : Callback<ListProgramResponse> {
override fun onResponse(call: Call<ListProgramResponse>, response: Response<ListProgramResponse>) {
Log.e("check", response.body()?.toString())
override fun onFailure(call: Call<ListProgramResponse>, t: Throwable) {
Toast.makeText(applicationContext, "Failure", Toast.LENGTH_SHORT).show()
t.printStackTrace()
}
})
response
data class ProgramBersedekahResponse(
#SerializedName("banner") val banner: String?,
#SerializedName("domainlembaga") val domainlembaga: String?,
#SerializedName("domainprogram") val domainprogram: String?,
#SerializedName("donate") val donatur: Int?
)
but it says java.lang.NumberFormatException: empty String and failure. did anyone know why? please help
Related
I've been developing an Android Q&A app using Jetpack Compose. I've been trying to make Post requests in Retrofit but the data I send isn't on my API website. I've succeeded in making Get requests though. I've read many documents but I cannot find out what is wrong with this code.
This is data class.
data class UsersEntity(
val id: Int? = null,
val name: String? = null,
val uid: String? = null
)
This is Service interface.
interface UserService {
#POST("createusers")
fun createUsers(#Body usersinfo: UsersEntity): Call<Unit>
}
When I click a button, I'd like to send data to the server. I get the log "Hi, good job" but I cannot see the data on my API.
Button(
onClick = {
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.*****.com/")
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
val service: UserService = retrofit.create(UserService::class.java)
val usersInfo = UsersEntity(
3, "Alex", "164E92FC-D37A")
service.createUsers(usersInfo).enqueue(object: Callback<Unit> {
override fun onResponse(call: Call<Unit>, response: Response<Unit>) {
Log.d("Hi", "good job")
}
override fun onFailure(call: Call<Unit>, t: Throwable) {
Log.d("Hi", "error")
}
})
}
I changed the code like this.
Button(
onClick = {
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.*****.com/")
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
thread {
try {
val service: UserService = retrofit.create(UserService::class.java)
val usersInfo = UsersEntity(
3, "Alex", "164E92FC-D37A")
service.createUsers(usersInfo).enqueue(object: Callback<ResponseBody> {
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
Log.d("Response", "${response.body()}")
}
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
Log.d("Hi", "error")
}
})
} catch (e: Exception) {
Log.d("response", "debug $e")
}
}
},
Could someone help me? Thank you.
I think your baseurl shouldn't end with a slash. Try this.
.baseUrl("https://api.*****.com")
And for your interface (also the Call<ResponseBody>):
interface UserService {
#POST("/createusers/")
fun createUsers(#Body usersinfo: UsersEntity): Call<ResponseBody>
}
Got some issues with this in the past so this might help. If not it atleasts cleans the code a bit :p
Also you can use ProxyMan to intercept your request and read what your application is actually sending to the server, might be a issue to find there!
Proxyman.io
I want to show response POST from retrofit. I don't really know how because my response are array but with POST.
this is how my response looks like
{
"message":[
"00",
"Get Success"
],
"result":{
"listProgram":[
{
"banner":"",
"area":"",
"domainlembaga":"",
"domainprogram":"",
"donate":0
{
.
.
.
]
service
interface Service {
#POST("program/list")
fun getProgram(#Body body: Pair<String, Int>, pair: Pair<String, Int>): Call<BaseBersedekahResponse<ListProgramBersedekahResponse>>
data
data class BaseBersedekahResponse<T>(
#SerializedName("message") val message: String?,
#SerializedName("result") val result: T?
)
data class ListProgramBersedekahResponse(
#SerializedName("listProgram") val listProgram: List<ProgramBersedekahResponse>?
)
data class ProgramBersedekahResponse(
#SerializedName("banner") val banner: String?,
#SerializedName("domainlembaga") val domainlembaga: String?,
#SerializedName("domainprogram") val domainprogram: String?,
#SerializedName("donate") val donatur: Int?
)
activity
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(APIUrl.BASEURL)
.addConverterFactory(GsonConverterFactory.create())
.build()
val apiService: Service = retrofit.create(Service::class.java)
val call: Call<BaseBersedekahResponse<ListProgramBersedekahResponse>> = apiService.getProgram(
"limit" to 1,
"group" to 4)
call.enqueue(object : Callback<BaseBersedekahResponse<ListProgramBersedekahResponse>> {
override fun onResponse(call: Call<BaseBersedekahResponse<ListProgramBersedekahResponse>, response: Response<BaseBersedekahResponse<ListProgramBersedekahResponse>>) {
val getProgram: List<ProgramBersedekahResponse?>? = response.body().result.listProgram
Toast.makeText(applicationContext, "success", Toast.LENGTH_SHORT).show()
}
override fun onFailure(call: Call<BaseBersedekahResponse<ListProgramBersedekahResponse>>, t: Throwable) {
Toast.makeText(applicationContext, "Failure", Toast.LENGTH_SHORT).show()
}
})
I actually planning it to show in RecyclerView, but I still don't know how to show it the response from POST. please help.
Your signatures should match each other. You should make your signatures same as the signature in your interface.
For your request body:
data class BersedekahRequest(
#SerializedName("limint") val limint: Int,
#SerializedName("group") val group: Int
)
then your interface:
#POST("program/list")
fun getProgram(#Body body: BersedekahRequest): Call<BaseBersedekahResponse<ListProgramBersedekahResponse>>
your rest service call:
val requestBody = BersedekahRequest(10,20)
val call: Call<BaseBersedekahResponse<ListProgramBersedekahResponse>> = apiService.getProgram(requestBody)
call.enqueue(object : Callback<BaseBersedekahResponse<ListProgramBersedekahResponse>> {
override fun onResponse(call: Call<BaseBersedekahResponse<ListProgramBersedekahResponse>, response: Response<BaseBersedekahResponse<ListProgramBersedekahResponse>>) {
val GetApps2: List<ProgramBersedekahResponse?>? = response.body().result.listProgram
Toast.makeText(applicationContext, "success", Toast.LENGTH_SHORT).show()
}
override fun onFailure(call: Call<ListProgramBersedekahResponse>, t: Throwable) {
Toast.makeText(applicationContext, "Failure", Toast.LENGTH_SHORT).show()
}
})
And I think one more problem you have.
fun getProgram(#Body body: ProgramBersedekahResponse?) this #Body is the body you will send via POST request, not your response body. If you do not send anything inside post body, make it empty, or give the appropriate request body since it seems like it is your response object right now.
I found some Api about Pokemon(https://pokeapi.co). And I try get data from this Api and it's work.
The data look like this
But I try to use name of data from Api to get some image with this path "api/v2/pokemon/{name}"
The problem is how can get name out of onResponse or do the other way to get name and image of Pokemon
MainActivity
val retrofit = Retrofit.Builder()
.baseUrl("https://pokeapi.co/")
.addConverterFactory(GsonConverterFactory.create())
.client(HTTPLogger.getLogger())
.build()
val jsonPlaceholderApi = retrofit.create(pokemonService::class.java)
val myCall: Call<PokemonInGen> = jsonPlaceholderApi.getGen(1)
myCall.enqueue(object : Callback<PokemonInGen> {
override fun onResponse(
call: Call<PokemonInGen>,
response: Response<PokemonInGen>
) {
val DataResponse: PokemonInGen = response.body()!!
Timber.i("on do Respon %s", DataResponse)
}
override fun onFailure(call: Call<PokemonInGen>, t: Throwable) {
Timber.i("on do ERROR")
}
})
My Service
interface pokemonService {
#GET("api/v2/generation/{id}")
fun getGen(
#Path("id") id: Int,
): Call<PokemonInGen>
#GET("api/v2/pokemon/{name}")
fun getArtwork(
#Path("name") name: String,
): Call<PokemonArtwork>
}
My Model Data class
data class PokemonInGen(
val pokemon_species: List<PokemonList>)
data class PokemonList(
val name: String,
val url: String,
)
To fetch Pokemon image you should create additional function in your MainActivity class
fun fetchPokemonArtwork(name: String) {
jsonPlaceholderApi.getArtwork(name).enqueue(object : Callback<PokemonArtwork> {
override fun onResponse(
call: Call<PokemonArtwork>,
response: Response<PokemonArtwork>
) {
// An artwork is successful fetched
val artwork = response.body()!!
}
override fun onFailure(call: Call<PokemonArtwork>, t: Throwable) {
// Handle a failure
}
})
}
You should call this function right after you fetched a Pokemon in generation
val myCall: Call<PokemonInGen> = jsonPlaceholderApi.getGen(1)
myCall.enqueue(object : Callback<PokemonInGen> {
override fun onResponse(
call: Call<PokemonInGen>,
response: Response<PokemonInGen>
) {
val DataResponse: PokemonInGen = response.body()!!
Timber.i("on do Respon %s", DataResponse)
// Extract name
val name = DataResponse.pokemon_species.first().name
// Fetch an artwork
fetchPokemonArtwork(name)
}
override fun onFailure(call: Call<PokemonInGen>, t: Throwable) {
Timber.i("on do ERROR")
}
})
P.S. I proceeded from the assumption that you've implemented PokemonArtwork class. Please let me know if you are facing difficulties in comments below.
P.S.S. It's not recommended to make network calls in Activity or Fragment classes. This guide to app architecture should help you to select correct app structure in your future releases.
You can using #Url to support dynamic link in retrofit. Example below:
interface pokemonService {
#GET
Call<PokemonResponse> getListPokemon(#Url String url);
}
And paste your url to browser to see data format.
I'm trying to do a POST request using Retrofit but I'm unable to make it work. It does work on Postman. I specified the header "Content-Type: application/json" and set my "email" and "password" parameters in the body and it works well.
But it doesn't on Android. Here are my codes :
private fun login() {
val user = User("test#gmail.com", "dsea2EcFI32\\\"af'xn")
this.service.login(user).enqueue(object : Callback<LoginResponse> {
override fun onResponse(call: Call<LoginResponse>, response: Response<LoginResponse>) {
if (response.code() == 200) {
// TODO
}
}
override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
// TODO
println(t.message)
}
})
}
The request :
#Headers("Content-Type: application/json")
#POST("/api/authentication/login")
fun login(#Body body: User): Call<LoginResponse>
User model
data class User(val email: String, val password: String)
LoginResponse :
class LoginResponse {
#SerializedName("user")
val user : UserResponse? = null
}
class UserResponse {
#SerializedName("id") val still : String = null
#SerializedName("firstName") val running : String = null
#SerializedName("lastName") val bicycle : String = null
#SerializedName("email") val walking : String = null
#SerializedName("token") val vehicle : String = null
}
In case the auth is a failure, the server sends me back an HTML page so the only error I have is
Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $
I already set it to true and it keeps saying me that the GSON parsed object isn't a JSON object but I know there's an Android code here
Can someone helps me finding it ?
PS : I even tried to send the body as a JSON object but same error
PS2 : might this be due to the password even If I added enough backspace to accept the special characters ? the real string is dsea2EcFI32"af'xn
EDIT :
As asked, here is my retrofit builder with the HTTPInterceptor
val client = OkHttpClient()
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
client.interceptors().add(interceptor)
val retrofit = Retrofit.Builder()
.baseUrl(BuildConfig.API_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
this.service = retrofit.create(LoginResponse::class.java)
I found the solution.
The issue was the password because it had backslashes and quotes inside of it.
Kotlin was doing a wrong parsing.
Convert your fun login object like below one.
#Headers("Content-Type: application/json")
#POST("/api/authentication/login")
fun login(#Body requestBody: RequestBody): Call<LoginResponse>
then create a fun like this
fun makeGSONRequestBody(jsonObject: Any?): RequestBody {
return RequestBody.create(MediaType.parse("multipart/form-data"), Gson().toJson(jsonObject))
}
you need to pass your User object like below
private fun login() {
val user = User("test#gmail.com", "dsea2EcFI32\\\"af'xn")
this.service.login(makeGSONRequestBody(user)).enqueue(object : Callback<LoginResponse> {
override fun onResponse(call: Call<LoginResponse>, response: Response<LoginResponse>) {
if (response.code() == 200) {
// TODO
}
}
override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
// TODO
println(t.message)
}
})
}
I am working on an android project. I use Kotlin and I'm just learning it. I want to use Retrofit 2 for my request. I use Java this method and it is done.
I want to register user my database. When I use my function, return success for web services but it saves the empty value and I take this error: "Expected BEGIN_OBJECT was string at line 3 column 1 path$". How we can solve this problem? Actually, I read and implementing other solutions but they don't work for me.
My API:
#POST("userregister.php")
fun doRegister(
#Body signupRequest: SignupRequest
): Call<SignupResponse> // body data
My API Service:
object ApiServiceWithOutRX {
private const val BASE_URL = "https://alperenyukselaltug.com/api/TurkAi/"
var gson = GsonBuilder()
.setLenient()
.create()
fun ApiCall() = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.client(ApiWorker.client)
.build()
.create(APIListWithOutRX::class.java)!!
}
And my register function:
val email = editTextMail!!.text.toString().trim()
val password = editTextPassword!!.text.toString().trim()
val json = JSONObject()
json.put("UserEmail", email)
json.put("UserPassword", password)
json.put("UserProfilePicture", "")
ApiServiceWithOutRX.ApiCall().doRegister(
SignupRequest(
email,
password,
""
)
).enqueue(object : Callback<SignupResponse> {
override fun onResponse(
call: Call<SignupResponse>,
response: Response<SignupResponse>
) {
Log.d("Response::::", response.body().toString())
val loginResponse: SignupResponse
loginResponse = response.body()!!
if (loginResponse.status) {
finish()
} else {
Toast.makeText(applicationContext, response.body()!!.message, Toast.LENGTH_LONG)
.show()
}
}
override fun onFailure(call: Call<SignupResponse>, t: Throwable) {
Toast.makeText(applicationContext, t.message, Toast.LENGTH_LONG).show()
}
})
My Model:
data class User(
#SerializedName("UserEmail")
val UserEmail: String?,
#SerializedName("UserPassword")
val UserPassword: String?,
#SerializedName("UserProfilePicture")
val UserProfilePicture: String?
)
class SignupResponse(val status: Boolean, val message:String, val data: User)
class SignupRequest(#SerializedName("UserEmail") var UserEmail: String,
#SerializedName("UserPassword") var UserPassword: String,
#SerializedName("UserProfilePicture") var UserProfilePicture: String)
I solve this problem. First, I return my server side a string with PHP in echo. I return a string value. So I change my #Post like this:
#FormUrlEncoded
#POST("userregister.php")
fun doRegister(
#Field("UserEmail") UserEmail:String,
#Field("UserPassword") UserPassword:String,
#Field("UserProfilePicture") UserProfilePicture:String
):Call<String>