3

This is the error I'm getting:

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $

JSON response I'm getting from Postman:

{
  "title": "test title",
  "body": "test body",
  "userId": 1,
  "id": 101
}

This is how I echoed the response from the rest API (used slim2 framework):

$app->post('/posts', function() use($app){
    $res = array(
        "title" => $app->request->post('title'),
        "body" => $app->request->post('body'),
        "userId" => 1,
        "id" => 101
        );
    echoResponse(201, $res);
});

echoResponse method:

function echoResponse($status_code, $response) {
    $app = \Slim\Slim::getInstance();
    $app->status($status_code);
    $app->contentType('application/json');

    echo json_encode($response);
}

The method where I call the API:

public void sendPost(String title, String body) {
    mAPIService.savePost(title, body, 1).enqueue(new Callback<Post>() {
        @Override
        public void onResponse(Call<Post> call, Response<Post> response) {
            Log.i(TAG, "post sendPost to onResponse.");
            if(response.isSuccessful()) {
                showResponse(response.body().toString());
                Log.i(TAG, "post submitted to API." + response.body().toString());
            }
        }

        @Override
        public void onFailure(Call<Post> call, Throwable t) {
            Log.e(TAG, "Unable to submit post to API.");
            Log.e(TAG, t.toString());
        }
    });
}

The APIServie interface:

public interface APIService {
@POST("/posts")
@FormUrlEncoded
Call<Post> savePost(@Field("title") String title,
                    @Field("body") String body,
                    @Field("userId") long userId);
}

How I got the retrofit instance:

mAPIService = ApiUtils.getAPIService();
public class ApiUtils {
    private ApiUtils() {}
    public static final String BASE_URL = "http://myurl/v1/";

    public static APIService getAPIService() {
        return RetrofitClient.getClient(BASE_URL).create(APIService.class);
    }

}
public class RetrofitClient {
   private static Retrofit retrofit = null;

   private static Gson gson = new GsonBuilder()
        .setLenient()
        .create();

   public static Retrofit getClient(String baseUrl) {
      if (retrofit==null) {
        retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();
      }
      return retrofit;
   }
}

Reason I posted all this was I couldn't find where the problem is because JSON response I'm getting from API looks ok, the way I called the API looks ok. There are many questions related to this can be found here. But I couldn't find the answer to my problem. Please find me a solution to this. Thanks

EDIT : @Darpan and @Fred was right. I enabled the logging for retrofit. this is what it says

D/OkHttp: --> POST http://myurl/posts http/1.1
D/OkHttp: Content-Type: application/x-www-form-urlencoded
D/OkHttp: Content-Length: 26
D/OkHttp: title=vz&body=gde&userId=1
D/OkHttp: --> END POST (26-byte body)
D/OkHttp: <-- 200 OK http://mywebsite/404/
    <html of my 404 page>
D/OkHttp: <-- END HTTP (2119-byte body) 

It's giving me my servers' 404.html file as the response. but When I call the same API from POSTMAN it's giving me the desired result.

So basically I can access and get the result from POSTMAN but cannot consume it from Android app using retrofit

Any idea how to fix it? what can be the problem?

itsChathurangaJ
  • 49
  • 1
  • 1
  • 11
  • I'm no php guru, but from the retrofit/gson error it sounds like you're entire json response is encoded as a whole string. Can you double check that? – Fred Mar 02 '17 at 08:44
  • @Fred I checked. in the response header it says "Content-Type →application/json". so I think there is no problem with that. I might be wrong, I don't know any other way to do it. I'm new to PHP and slim – itsChathurangaJ Mar 02 '17 at 09:12
  • I doubt the response you shared was the response you are getting in case of retrofit. Can you enable logging for retrofit, and see what your API call is getting in response? It must be a string, ie your response is throwing some error, hence not starting with a "{" – Darpan Mar 02 '17 at 09:32
  • @Darpan Thank you for the logging retrofit idea. that works. you were right. please check the edit down in the post – itsChathurangaJ Mar 02 '17 at 10:41
  • remove v/ from base url and put it in @POST("v/posts/"): See this answer http://stackoverflow.com/questions/42430403/retrofit-android-basic-and-simple-issue/42444365#42444365 – Muhammad Haseeb Khan Mar 03 '17 at 05:50
  • @MuhammadHaseebKhan thanks a lot... it worked perfectly. post this as the answer. – itsChathurangaJ Mar 04 '17 at 09:02
  • @ChathurangaJayanidu You are most welcome. :) – Muhammad Haseeb Khan Mar 04 '17 at 09:04
  • Check this https://stackoverflow.com/a/59434336/6667442 – Ketan Ramani Dec 21 '19 at 07:31

3 Answers3

2

Remove the last / from your base url http://myurl/v1/

That's why it is throwing 404.

BNK
  • 23,994
  • 8
  • 77
  • 87
Darpan
  • 5,623
  • 3
  • 48
  • 80
1

Create bellow class and change Call<Post> to Call<MyResponse>

public class MyResponse {

    @SerializedName("result")
    private String result;

    @SerializedName("data")
    private Data data;

    public class Data {

        @SerializedName("title")
        @Expose
        private String title;

        @SerializedName("body")
        @Expose
        private String body;

        @SerializedName("userId")
        @Expose
        private String userId;

        @SerializedName("id")
        @Expose
        private String id;

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getBody() {
            return body;
        }

        public void setBody(String body) {
            this.body = body;
        }

        public String getUserId() {
            return userId;
        }

        public void setUserId(String userId) {
            this.userId = userId;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }
    }

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    public Data getData() {
        return data;
    }

    public void setData(Data data) {
        this.data = data;
    }
}

Your should change your json format like this

{
    "result" : "success",
    "data" : {
            "title":"title",
            "body":"body",
            "user_id":"userid",
            "id":"id"
    }   
}

Now you can access it in response like this MyResponse res= response.body();

And also print response like this Log.d("response", new Gson().toJson(res));

Sumit Bhatt
  • 718
  • 4
  • 19
1

I was getting the same error, and my root cause was that my Api was expecting a call with https://my.url.com and Android was doing the request with http://my.url.com. We had a look at the logs and the server was treating the request as a GET and not a POST.

After changing the url to https:// it worked fine. Hope this helps someone else

voghDev
  • 5,641
  • 2
  • 37
  • 41