anta40
anta40

Reputation: 6743

Cannot call GItHub search user API with Retrofit

I'm experimenting with GitHub search users API. My goal is to write a simple app: type a username and any GitHub username related with it will be displayed on RecyclerView (using MVVM pattern).

For example, here's how to search username clive:

https://api.github.com/search/users?q=clive

And here are relevant parts the code:

APIConfig.java

public class APIConfig {

    public static final String BASE_URL = "https://api.github.com";
    public static final String END_POINT_SEARCH_USERS = "/search/users";

}

APIEndPoint.java

import com.divbyzero.app.githubusersearch.model.User;

import java.util.List;

import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;

public interface APIEndPoint {

    @GET(APIConfig.END_POINT_SEARCH_USERS)
    Call<List<User>> getSearchResult(@Query("q") String param);

}

User.java

    package com.divbyzero.app.githubusersearch.model;

    import com.google.gson.annotations.Expose;
    import com.google.gson.annotations.SerializedName;

    public class User {

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

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

        public void setLogin(String login){
            this.login = login;
        }

        public void setAvatarUrl(String url){
            this.avatar_url = url;
        }

        public String getLogin(){
            return login;
        }

        public String getAvatarUrl(){
            return avatar_url;
        }

        public User(String login, String url){
            this.login = login;
            this.avatar_url = url;
        }
    }

UserViewModel.java

  package com.divbyzero.app.githubusersearch.viewmodel;

    import android.util.Log;

    import androidx.lifecycle.LiveData;
    import androidx.lifecycle.MutableLiveData;
    import androidx.lifecycle.ViewModel;

    import com.divbyzero.app.githubusersearch.api.APIEndPoint;
    import com.divbyzero.app.githubusersearch.api.APIService;
    import com.divbyzero.app.githubusersearch.model.User;

    import java.util.ArrayList;
    import java.util.List;

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

    public class UserViewModel extends ViewModel {

        private MutableLiveData<ArrayList<User>> mutableLiveData = new MutableLiveData<>();

        public void setSearchResult(String param){
            Retrofit retrofit = APIService.getRetrofitService();
            APIEndPoint apiEndpoint = retrofit.create(APIEndPoint.class);
            Call<List<User>> call = apiEndpoint.getSearchResult(param);
            call.enqueue(new Callback<List<User>>() {
                @Override
                public void onResponse(Call<List<User>> call, Response<List<User>> response) {
                    mutableLiveData.setValue((ArrayList<User>) response.body());
                    Log.d("DBG", "OK");
                }

                @Override
                public void onFailure(Call<List<User>> call, Throwable t) {
                    Log.d("DBG", "Failed");
                }
            });
        }

        public LiveData<ArrayList<User>> getSearchResult(){
            return mutableLiveData;
        }
    }

Full source code: https://github.com/anta40/GithubUserSearch

When I type any username on the SearchView and hit the ENTER key, no search result is displayed (the recyclerview is still empty). After further inspection, I found that "DBG: Failed" was shown on logcat, which means the GitHub API wasn't properly called. How to fix this?

Upvotes: 0

Views: 883

Answers (1)

Boken
Boken

Reputation: 5362

Error

Error which appear in your view model is:

Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $

So there is a problem with parsing your response. You are receiving it, but parsing wrong.

Reason

After calling this GET request (which you are using):

https://api.github.com/search/users?q=some_name

I am receiving:

{
  "total_count": 0,
  "incomplete_results": false,
  "items": [

  ]
}

Where is problem

Base on receiving .json I see, that as a root element is JSON OBJECT. In you ViewModel you are expecting List<User> (JSON ARRAY) which is not true. You are receiving object with 3 fields. And one of this field is your List<User>.

Fix - description

You have to create new model class describing data which you are receiving. To parse (from json to Java) all received received data, it should contains 3 fields.

Fix - code

Example of your new class:

public class GitHubResponse {
    private long totalCount;
    private boolean incompleteResults;
    private List<User> items;
}

and use this class eveywhere in ViewModel and APIEndPoint.java. To access data - ad getters to this class.

General project hints/tips

  • Reformat code (Ctrl + Alt + L)

  • Add "start" state (beacuse after starting app view is empty)

  • Add empty state (when received data is empty)

  • Add loading state (when you are loading data and waiting for the response)

  • Add error state (when connection failed or some problem with parsing data)

Upvotes: 1

Related Questions