3

I've built a simple API using Laravel and it is working fine. My Android app should consume data from this API, but for some JSON response I'm getting an error

Expected BEGIN_OBJECT but was STRING at line 1 column 1 path

Before getting this error, the error was the one below:

Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path

Then I setLenient(true) to solve it.

I've seen in many other posts that the problem is a malformed JSON, but it appears to be all good.

JSON response that gives me error:

{
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImRhMWUxNzU4YmI1YTFjMjAzZDI1MDk5OTM4YTljMjgwNDUyMjYzMDFhNjZiZmViZmJlMTQyY2FmNGU4OGUwMzc2NTZkN2RmZjI4NDUxMTEzIn0.eyJhdWQiOiIxIiwianRpIjoiZGExZTE3NThiYjVhMWMyMDNkMjUwOTk5MzhhOWMyODA0NTIyNjMwMWE2NmJmZWJmYmUxNDJjYWY0ZTg4ZTAzNzY1NmQ3ZGZmMjg0NTExMTMiLCJpYXQiOjE1NTE3OTIzMzAsIm5iZiI6MTU1MTc5MjMzMCwiZXhwIjoxNTgzNDE0NzMwLCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.bi4l9mpUDLoYMLWwd1JyCAfoN2GtwpnpEmGnzsoDoIP_rcTWfT9IsixX4iwtbjSdOTBFkqSD9oGz8KncI24spgnKhofZelClSP6tNtI6P8q2b_PmnefytmNfu_fWBAvSTD2Tia8-cMCu_eF9QfNoOv_9JCYAaY__DY2W_zI3u8uLv25EZQPgBiW7MIT_gm9ZnD6JJlCL4rkgUuhdDG8lkjHCryAYVBqXsGLizl6YdgBp8zMYzONzjxT4nhTARL_aywE9ejZCt5Mkh5qvoGms4zkMMAW0OIYVP_puB7MSPJAriCR1kaBO06MSNGcfAdorn5VDpfwFV8t25mftOeaM1x8IvWT1K0_Hi0BtdV2twtJ-_uHcmIn8QiF3Tc6On7YWWWGEfJw0vAGqK5RaYtWVSo5iWbAiD5rsmCQRQDsg4GnEH9AnYHjcjortBe01YuimQ4TMSIgWLpRfExwcPgQkonklWqODcE8nvuWzyKUirmm56gGj1wBZciqrYsDRTImP4Ntv1Q5Tb3r2PoFlqxfn3_qux1OQpTyzHGEOEaE9ZQnNoELjwGd5nUuFOYCOdwafIUsG0atHtoPBj_S6jTsJJdIWqQzCexchpkwBUgP5i6o1QCai7BcOnTXKJ3V6kV17SGtiP7gqTM9fvESD0BIuK4Xd0dsA8mc67_HwLJyhpXM",
    "token_type": "Bearer",
    "expires_at": "2019-03-19"
}

Working JSON Response:

{
    "message": "The given data was invalid.",
    "errors": {
        "username": [
            "The username has already been taken."
        ]
    }
}

I've tested JSON with JSONLint and it says it's all good with JSON

Not Working - Laravel JSON Response

return response()->json([
       'access_token' => $tokenResult->accessToken,
        'token_type' => 'Bearer',
        'expires_at' => Carbon::parse(
            $tokenResult->token->expires_at
        )->toDateString()
        ], 200);

Working - Laravel JSON Response

    return response()->json([
        'message'=>'Cadastro realizado.',
        'user_id' => $user->id
    ], 201);

Android - Signin

btnSignin.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d(TAG, "onClick: " + etSigninUser.getText().toString());
            Log.d(TAG, "onClick: " + etSigninPassword.getText().toString());
            Call<LoginResponse> call = apiService.userLogin(
                    etSigninUser.getText().toString(),
                    etSigninPassword.getText().toString(),
                    false
            );

            call.enqueue(new Callback<LoginResponse>() {
                @Override
                public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
                    Log.d(TAG, "onResponse: " + response.code());
                }

                @Override
                public void onFailure(Call<LoginResponse> call, Throwable t) {
                    Log.d(TAG, "onFailure: " + t.toString() + " " + t.getCause());
                    Log.d(TAG, "onFailure: " + t.toString());
                }
            });
        }
    });

Android - LoginResponse Model

    public class LoginResponse {

    @SerializedName("access_token")
    @Expose
    private String accessToken;
    @SerializedName("token_type")
    @Expose
    private String tokenType;
    @SerializedName("expires_at")
    @Expose
    private String expiresAt;

    public String getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    public String getTokenType() {
        return tokenType;
    }

    public void setTokenType(String tokenType) {
        this.tokenType = tokenType;
    }

    public String getExpiresAt() {
        return expiresAt;
    }

    public void setExpiresAt(String expiresAt) {
        this.expiresAt = expiresAt;
    }
}

**Android - Retrofit 2 Call **

@FormUrlEncoded
@POST("auth/login")
Call<LoginResponse> userLogin(
        @Field("username") String username,
        @Field("password") String password,
        @Field("remember_me") boolean remember_me
);

I can't see what is wrong with my code, everything appears to be good, why am I getting this error? Is JSON malformed?

EDIT 1 - Postman

Postman

  • Have you tested in postman? – Kishore Jethava Mar 05 '19 at 13:46
  • Yes, it works fine in postman. – Alan Godoi da Silveira Mar 05 '19 at 13:47
  • check, Is it returning 200 OK in postman? – Kishore Jethava Mar 05 '19 at 13:48
  • @KishoreJethava see my edit – Alan Godoi da Silveira Mar 05 '19 at 13:52
  • 2
    Couldn't point any issue in this. Strange to see the error. – Rohit5k2 Mar 05 '19 at 14:02
  • Take a look on [Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $](https://stackoverflow.com/questions/39918814/use-jsonreader-setlenienttrue-to-accept-malformed-json-at-line-1-column-1-path) and [Retrofit2.0 gets MalformedJsonException while the json seems correct?](https://stackoverflow.com/questions/35984898/retrofit2-0-gets-malformedjsonexception-while-the-json-seems-correct) – Michał Ziober Mar 05 '19 at 16:23
  • I tested it, it is in my question. – Alan Godoi da Silveira Mar 05 '19 at 18:30
  • Can't find anything wrong with this. Only thing that comes to mind is that you're actually not getting what you expect due to some other error. Did you try adding logs to Retrofit to see what response to you actually get? From my experience postman adds some default headers that Retrofit doesn't and some servers can't cope with this and return some unexpected response. – Fred Mar 07 '19 at 14:20
  • @Alan, have you fixed this bug? In case it still does not work, you need to log `JSON` payload and use [jsonformatter](https://jsonformatter.curiousconcept.com/) to validate it. In case it is not valid you need to preremove invalid characters. – Michał Ziober Mar 07 '19 at 20:56

1 Answers1

0

I had this problem and it took me a lot of time to figure it out.

I found a solution here: https://stackoverflow.com/a/56903479/3971619

TLDR: The BASE_URL variable used to create the Retrofit object should not have anything after the /

Replace:

val authApiService = Retrofit.Builder()
    .baseUrl("https://test.com/api/test") //There is path after the /
    .addConverterFactory(GsonConverterFactory.create(gson))
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build().create(AuthService::class.java)

By

val authApiService = Retrofit.Builder()
    .baseUrl("https://test.com/") //It should only be the base url without a path
    .addConverterFactory(GsonConverterFactory.create(gson))
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build().create(ServiceClass::class.java)
Clément Bisaillon
  • 4,559
  • 7
  • 27
  • 49