android - PHP API not working in conjuntion with retrofit/gson

I'm having trouble getting my rest API to work with POST requests from my android app using retrofit/gson. What the REST API is supported to do, is take in very basic JSON decode it, run a series of SQL queries on it then return formatted JSON data back to the app.

I know the problem isn't with the API logic, the API works fine when I hard code the incoming JSON data or hard code the JSON response Into the PHP. The problems start when I need to deliver the JSON with a POST request from the app. I always get the following excptions:FATAL EXCEPTION: DefaultDispatcher-worker-1 or FATAL EXCEPTION: DefaultDispatcher-worker-2 the incoming JSON comes from the app.

I have tried 3 ways of receiving incoming JSON. the first being using the $jsonobj = http_get_request_body();function the second being $jsonobj = file_get_contents('php://input'); and the third being $jsonobj = $_POST['code']; this last one is interesting. I have no idea if whats in ['here'] maters or what the name would be so I could use it. I have tried changing the ['text'] in here a few times and it hasn't worked.

here an overview of my PHP script before we go on.

//database config here.

if($_SERVER["REQUEST_METHOD"] == "POST"){
    //method of reciving JSON here.
    $obj = json_decode($jsonobj);

    //SQL logic here.
    echo json_encode($return);
}

this works if not for the JSON receiver.

There is also a pretty good chance I'm not even sending JSON at all let alone valid JSON. I know there are ways of logging the outbound JSON but for the life of me, I can't get them to work. So here I will post bits of my android code.

my API interface

interface API {
    @POST("posttest.php")
    suspend fun postit(@Body post: String): Phone
}

and I use said interface in this context

val api = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(API::class.java)

    GlobalScope.launch(Dispatchers.IO) {
        val response = api.postit(test)

        try {
               //logic
        }catch (e: Exception){
            //error handling
        }
    }

}

I want to draw the JSON from a room database but I haven't done that yet so I just have the JSON hardcoded; it looks like this.

    private var test = "[\"text1\", \"text2\", \"text3\"]"

thank you for your time.

Answer

Solution:

Below is the code that works and serves only to establish application connection with API. everything else you will adapt to your own needs (retrofit requests, response, json encoding)

Follow logs in Android app

I strongly recommend that you do not query the database without data validation and that you use PDO

And it would be better to use some php framework for api like Slim, Laravel, Lumen

You can POST request with one of the most used types:

  • application/x-www-form-urlencoded = parameters encoded
  • application/json = send json data //Used for your case
  • multipart/form-data = files like images

Your PHP script should be like this

if($_SERVER["REQUEST_METHOD"] == "POST"){
    
    //TODO this is only example to get and return json data
    
    $jsonobj = file_get_contents('php://input');
    $json = json_decode($jsonobj);
    
    $response = array(
        "raw" => $jsonobj,
        "json" => $json
    );
    
    echo json_encode($response);
}else{
    //Send a 405 Method Not Allowed
    http_response_code(405);
    exit;
}

Interface Api

interface API {
    @POST("posttest.php")
    suspend fun postIt(@Body requestBody: RequestBody): Response<ResponseBody>
}

and main

val api = Retrofit.Builder()
                .baseUrl(BASE_URL)
                //.addConverterFactory(GsonConverterFactory.create())
                .build()
                .create(API::class.java);

        val test = "[\"text1\", \"text2\", \"text3\"]";  //hardcoded by you
        val requestBody = test.toRequestBody("application/json".toMediaTypeOrNull())

        GlobalScope.launch(Dispatchers.IO) {
            val response = api.postIt(requestBody)
            //withContext(Dispatchers.Main) {
                try {
                    if (response.isSuccessful) {
                        Log.i("RESPONSE", "DATA: " + response.body()?.string());
                    } else {
                        Log.i("RESPONSE", "ERROR: " + response.errorBody()?.string());
                    }

                    Log.i("RESPONSE", "RAW: " + response.raw());
                } catch (e: Exception) {
                    e.printStackTrace();
                    //error handling
                }
            //}
        }

Answer

Solution:

as It turned out the problem was with my PHP API <{-code-1}>{-code-1} big thanks to user:404438 @kylexy1357 for giving me the logging {-code-1} so I could see whats up

his <{-code-1}>{-code-1}

<{-code-1}>val gson = GsonBuilder()
                .setLenient()
                .create()

  val builder = OkHttpClient().newBuilder()
        builder.readTimeout(120, TimeUnit.SECONDS)
        builder.connectTimeout(30, TimeUnit.SECONDS)

        if (BuildConfig.DEBUG) {
            val interceptor = HttpLoggingInterceptor()
            interceptor.level = HttpLoggingInterceptor.Level.BASIC
            builder.addInterceptor(interceptor)
        }
  val client = builder.build()


  val retrofit = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .client(client)
                .build()

Source