6

I am using retrofit to create an Android Client for the Reddit. At logcat to get the toke is work fine, but when I am trying to get the information of the login user, I am getting "404 Not Found". Here is my logcat:

D/OkHttp: --> POST https://oauth.reddit.com/api/v1/me http/1.1
D/OkHttp: Content-Length: 0
D/OkHttp: Authorization: bearer myToken
D/OkHttp: User-Agent: MyRedditClient/0.1 by myusername
D/OkHttp: --> END POST
D/OkHttp: <-- 404 Not Found https://oauth.reddit.com/api/v1/me (677ms)

Here is my code:

import java.io.IOException;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class ServiceAuthGenerator {

    public static final String API_BASE_URL = "https://www.reddit.com/";

    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

    private static Retrofit.Builder builder =
            new Retrofit.Builder()
                    .baseUrl(API_BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create());

    public static <S> S getTokenService(Class<S> serviceClass) {
        return getTokenService(serviceClass, null, null);
    }

    public static <S> S getTokenService(Class<S> serviceClass, String username, String password) {
        if (username != null && password != null) {
            String credentials = username + ":" + password;
            final String basic =
                    "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);

            httpClient.addInterceptor(new Interceptor() {
                @Override
                public Response intercept(Interceptor.Chain chain) throws IOException {
                    Request original = chain.request();

                    Request.Builder requestBuilder = original.newBuilder()
                            .header("Authorization", basic)
                            .header("Accept", "application/json")
                            .method(original.method(), original.body());

                    Request request = requestBuilder.build();
                    return chain.proceed(request);
                }
            });
        }

        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        OkHttpClient client = httpClient.addInterceptor(interceptor).build();
        Retrofit retrofit = builder.client(client).build();
        return retrofit.create(serviceClass);
    }

}

import java.io.IOException;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class ServiceInfoGenerator {

    public static final String API_BASE_URL = "https://oauth.reddit.com/";

    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

    private static Retrofit.Builder builder =
            new Retrofit.Builder()
                    .baseUrl(API_BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create());

    public static <S> S retrieveInfoService(Class<S> serviceClass) {
        return retrieveInfoService(serviceClass, null, null);
    }

    public static <S> S retrieveInfoService(Class<S> serviceClass, final String authToken, final String username) {
        if (authToken != null && username != null) {
            httpClient.addInterceptor(new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request original = chain.request();

                    // Request customization: add request headers
                    Request.Builder requestBuilder = original.newBuilder()
                            .header("Authorization", " bearer "+authToken)
                            .header("User-Agent", "MyRedditClient/0.1 by "+username)
                            .method(original.method(), original.body());

                    Request request = requestBuilder.build();
                    return chain.proceed(request);
                }
            });
        }

        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);

        OkHttpClient client = httpClient.addInterceptor(interceptor).build();
        try {
            client.interceptors().add(new UserAgentInterceptor(username));
        } catch (Exception e){
            Log.i("ServiceInfoGenerator", "retrieveInfoService: "+e.getMessage());
        }
        Retrofit retrofit = builder.client(client).build();
        return retrofit.create(serviceClass);
    }
}

import java.util.Map;

import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.Headers;
import retrofit2.http.POST;
import retrofit2.http.QueryMap;

public interface MyApiRetrofit {

    @POST("/api/v1/access_token")
    @FormUrlEncoded
    Call<Authorize> accessToken(@Field(("grant_type")) String grantType, @Field(("username")) String username, @Field(("password")) String password);

    @POST("/api/v1/me")
    Call<Authorize> retrieveMyInfo();

}

import android.os.AsyncTask;
import android.util.Log;

import com.havistudio.myreddit.api.Authorize;
import com.havistudio.myreddit.api.MyApiRetrofit;

import java.io.IOException;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class TestAPITask2 extends AsyncTask<Void, Void, Void> {

    private static final String TAG = "TestAPITask2";
    private String myAccessToken;
    private String myRefreshToken;

    @Override
    protected Void doInBackground(Void... voids) {

        MyApiRetrofit loginService = ServiceAuthGenerator.getTokenService(MyApiRetrofit.class, "client_id", "client_secret");
        Call<Authorize> call = loginService.accessToken("password", "myusername", "mypassword");
        call.enqueue(new Callback<Authorize>() {
            @Override
            public void onResponse(Call<Authorize> call, Response<Authorize> response) {
                if (response.isSuccessful()) {
                    // user object available
                    Log.i(TAG, "isSuccessful");
                    Authorize temp = response.body();
                    myAccessToken = temp.getAccessToken();
                    Log.i(TAG, temp.toString());

                    MyApiRetrofit myInfoService = ServiceInfoGenerator.retrieveInfoService(MyApiRetrofit.class, myAccessToken, "myusername");
                    Call<Authorize> call2 = myInfoService.retrieveMyInfo();
                    try {
                        Authorize user = call2.execute().body();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                } else {
                    // error response, no access to resource?
                    Log.i(TAG, "error response");
                }
            }

            @Override
            public void onFailure(Call<Authorize> call, Throwable t) {
                // something went completely south (like no internet connection)
                Log.d(TAG, t.getMessage());
            }
        });


        return null;
    }


}

I am following the instructions from this here. My retrofit version is:

compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'

Last log:

10-15 13:17:41.434 9968-9968 D/OkHttp: --> POST https://oauth.reddit.com/api/v1/me http/1.1
10-15 13:17:41.434 9968-9968 D/OkHttp: Content-Length: 0
10-15 13:17:41.434 9968-9968 D/OkHttp: Authorization: bearer tokenToken
10-15 13:17:41.434 9968-9968 D/OkHttp: User-Agent: MyRedditClient/0.1 by myusername
10-15 13:17:41.434 9968-9968 D/OkHttp: --> END POST (0-byte body)
10-15 13:17:41.988 9968-9968 D/OkHttp: <-- 404 Not Found https://oauth.reddit.com/api/v1/me (553ms)
10-15 13:17:41.988 9968-9968 D/OkHttp: Content-Type: application/json; charset=UTF-8
10-15 13:17:41.988 9968-9968 D/OkHttp: x-frame-options: SAMEORIGIN
10-15 13:17:41.988 9968-9968 D/OkHttp: x-content-type-options: nosniff
10-15 13:17:41.988 9968-9968 D/OkHttp: x-xss-protection: 1; mode=block
10-15 13:17:41.989 9968-9968 D/OkHttp: expires: -1
10-15 13:17:41.989 9968-9968 D/OkHttp: cache-control: private, s-maxage=0, max-age=0, must-revalidate, max-age=0, must-revalidate
10-15 13:17:41.990 9968-9968 D/OkHttp: x-ratelimit-remaining: 598.0
10-15 13:17:41.990 9968-9968 D/OkHttp: x-ratelimit-used: 2
10-15 13:17:41.990 9968-9968 D/OkHttp: x-ratelimit-reset: 136
10-15 13:17:41.990 9968-9968 D/OkHttp: set-cookie: loid=Fsx2GnGYmufCQZ6cfT; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Mon, 15-Oct-2018 10:17:44 GMT; secure
10-15 13:17:41.991 9968-9968 D/OkHttp: set-cookie: loidcreated=2016-10-15T10%3A17%3A44.173Z; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Mon, 15-Oct-2018 10:17:44 GMT; secure
10-15 13:17:41.991 9968-9968 D/OkHttp: x-ua-compatible: IE=edge
10-15 13:17:41.991 9968-9968 D/OkHttp: set-cookie: loid=Q52c9gouzuGGdg7UXW; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Mon, 15-Oct-2018 10:17:44 GMT; secure
10-15 13:17:41.991 9968-9968 D/OkHttp: set-cookie: loidcreated=2016-10-15T10%3A17%3A44.189Z; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Mon, 15-Oct-2018 10:17:44 GMT; secure
10-15 13:17:41.991 9968-9968 D/OkHttp: X-Moose: majestic
10-15 13:17:41.991 9968-9968 D/OkHttp: Content-Length: 38
10-15 13:17:41.992 9968-9968 D/OkHttp: Accept-Ranges: bytes
10-15 13:17:41.992 9968-9968 D/OkHttp: Date: Sat, 15 Oct 2016 10:17:44 GMT
10-15 13:17:41.992 9968-9968 D/OkHttp: Via: 1.1 varnish
10-15 13:17:41.992 9968-9968 D/OkHttp: Connection: keep-alive
10-15 13:17:41.992 9968-9968 D/OkHttp: X-Served-By: cache-ams4426-AMS
10-15 13:17:41.992 9968-9968 D/OkHttp: X-Cache: MISS
10-15 13:17:41.992 9968-9968 D/OkHttp: X-Cache-Hits: 0
10-15 13:17:41.992 9968-9968 D/OkHttp: X-Timer: S1476526664.126987,VS0,VE109
10-15 13:17:41.993 9968-9968 D/OkHttp: Server: snooserv
10-15 13:17:42.002 9968-9968 D/OkHttp: {"message": "Not Found", "error": 404}
10-15 13:17:42.002 9968-9968 D/OkHttp: <-- END HTTP (38-byte body)
KostasC
  • 1,076
  • 6
  • 20
  • 40

5 Answers5

1

One of the possible cause may be your BASE URL.

According to Retrofit 2, base url must not end with '/'.

Please remove '/' from base URL and try one.

In Retrofit 1.9, it was working fine.

Cheers!!!

Amit Goyal
  • 56
  • 2
  • Please share logs of your request using library compile 'com.squareup.okhttp3:logging-interceptor:3.4.1' – Amit Goyal Oct 15 '16 at 10:09
  • It will give the request and response with Header information. To use this library call :: HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); // set your desired log level logging.setLevel(HttpLoggingInterceptor.Level.BODY); okHttpClientBuilder.interceptors().add(logging); – Amit Goyal Oct 15 '16 at 10:11
  • I have edit my post and add the new output of the log. – KostasC Oct 15 '16 at 10:20
  • Your URL is wrong "https:// oauth.reddit.com/api/v1/me". It must be "https:// www.reddit.com/api/v1/me" . ***Note Space added after https://. You need to remove this. – Amit Goyal Oct 15 '16 at 10:25
  • if I change the url to "https://www.reddit.com/api/v1/me", I getting "403 Forbidden". – KostasC Oct 15 '16 at 10:29
  • 403 Forbidden means you don't have access (Access Denied). Now, to connect to reddit, you need to first hit the OAuth Request, which will return you an Authrization Token, Using that token you need to get logged in user's profile. This authorization token must go as Header of /api/v1/me request. – Amit Goyal Oct 15 '16 at 10:34
  • But I already have the Authorization at my Header! You can see it at the log, I have already provide! – KostasC Oct 15 '16 at 10:37
  • Your Authorization header must be like this: Authorization: "bearer tokenToken" or Authorization: 'bearer tokenToken' – Amit Goyal Oct 15 '16 at 10:47
1

Your API call for endpoint /api/v1/me is POST method

@POST("/api/v1/me")
Call<Authorize> retrieveMyInfo();

According to their documentation for enpoint /api/v1/me you should use GET requests.

@GET("/api/v1/me")
Call<Authorize> retrieveMyInfo();

I didn't test that solution but it seems to be the cause for 404, as in another post it solved the problem (for python).

Community
  • 1
  • 1
Luke
  • 2,539
  • 2
  • 23
  • 40
0

Due to how Retrofit 2.0 uses Http Resolve for resolving the uri scheme of your endpoints, if you specify the baseurl like this http://hello.com and the endpoint URL as /world/foo it will break.

You need to use base URL http://hello.com/ and endpoint URL world/foo.

The / makes the difference.

if it helps you please inform me or i will give you another solution. Your problem is same as this problem i think: Link

And you can check this issues : Link

Community
  • 1
  • 1
Jamil Hasnine Tamim
  • 4,389
  • 27
  • 43
0

@POST("api/v1/me")

remove "/" at first character url because retrofit 2.0 need BASEURL must end with "/".. I can't find others problem in your code. You should check your Header if there is any null value or check back the API link

ZeroOne
  • 8,996
  • 4
  • 27
  • 45
0

I finally find my solution! I was making the call with wrong grant_type! I change it, and now it is working!

KostasC
  • 1,076
  • 6
  • 20
  • 40