Ad

HTTP 401 - Empty Recyclerview With RxJava2 And Retrofit2 In MVVM Patterns

I am pretty new to MVVM Patterns and calling API with RxJava2 and Retrofit2. I'm trying to call API from Unsplash API I have no idea what should I do, I've looked over a lot of tutorials but no solution what is happening.

Here is where I provide APIService and OkHttpClient and Retrofit:

 @Provides
@Singleton
fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor {
    val interceptor = HttpLoggingInterceptor()
    interceptor.level = HttpLoggingInterceptor.Level.BODY
    return interceptor
}

@Provides
@Singleton
fun provideOkHttpClient(httpLoggingInterceptor: HttpLoggingInterceptor): OkHttpClient {
    val okHttpClient = OkHttpClient.Builder()
    okHttpClient.apply {
        if (BuildConfig.DEBUG) {
            addNetworkInterceptor(StethoInterceptor())
            addInterceptor(httpLoggingInterceptor)
        }
    }
    return okHttpClient.build()
}

    @Provides
@Singleton
fun provideApiService(okHttpClient: OkHttpClient): PhotoService {
    val retrofit = Retrofit.Builder()
        .baseUrl("https://api.unsplash.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .client(okHttpClient)
        .build()

    return retrofit.create(PhotoService::class.java)
}

PhotoService:

   @GET("photos")
fun getPhotos(@Query("page") page: Int = 1): Observable<List<Photo>>

PhotoRepository:

  fun getPhotos() : PhotoService {
    return photoApiService
}

ViewModel:

  //=======================================================
//                  DISPOSABLE
//=======================================================
private var disposable: Disposable? = null


//=======================================================
//         GET PHOTOS
//=======================================================
private val photoLive = MutableLiveData<List<Photo>>()
private val photoData: LiveData<List<Photo>>
get() = photoLive

@SuppressLint("LogNotTimber", "CheckResult")
fun getPhotos(): LiveData<List<Photo>> {
   disposable = photoRepository.getPhotos().getPhotos()
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(
       {
               it -> photoLive.value = it
       },
       {
               it -> if (it != null)
       {
               Log.e(TAG,Log.getStackTraceString(it))
       }
       })
    return photoData
}

And Fragment where I set adapter:

 private fun setPhotos() {
    viewModel.getPhotos().observe(this, Observer<List<Photo>> {
        it -> rvListPhoto.adapter = PhotosAdapter(it)
    })
}

I think code from Adapter is not necessarily to put it. Because the error is from the other side but I don't know where is the problem.

And if it does matters here is the error:

retrofit2.adapter.rxjava2.HttpException: HTTP 401 
    at retrofit2.adapter.rxjava2.BodyObservable$BodyObserver.onNext(BodyObservable.java:54)
    at retrofit2.adapter.rxjava2.BodyObservable$BodyObserver.onNext(BodyObservable.java:37)
    at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:44)
    at io.reactivex.Observable.subscribe(Observable.java:12005)
    at retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:34)
    at io.reactivex.Observable.subscribe(Observable.java:12005)
    at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
    at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:571)
    at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
    at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:764)
Ad

Answer

Looking at the documentation of unsplash, seems like you need to pass client_id with your query as a query parameter like below

https://api.unsplash.com/photos/?client_id=YOUR_ACCESS_KEY

This client_id can be found by user authentication api at https://unsplash.com/oauth/

Check https://unsplash.com/documentation#user-authentication for more information.

Ad
source: stackoverflow.com
Ad