grapi icon indicating copy to clipboard operation
grapi copied to clipboard

Goodreads unofficial android SDK ๐Ÿ“š

good reads api

Since Goodreads retire their api, this project should be considered deprecated as well. ๐Ÿ›‘


License: MIT made with Kotlin GitHub release GitHub stars

Goodreads unofficial android SDK.

Features

SDK handles login via OAuth with access token storage management and allow you to make requests to goodreads api with no pain. All code written in modern Kotlin. ๐Ÿš€

Currently supported api methods:

Iโ€™m currently adding the rest of the methods, so if you have feature requests or pull requests or just a comments - open an issue and I will try to help you. RFC.

Implementation details Medium Post

Setup

  1. Make sure you have the jitpack repo in your project level build.gradle :
allprojects {
    repositories {

        maven { url 'https://jitpack.io' }
    }
}
  1. Add the dependency to your app build.gradle :
implementation 'com.github.intmainreturn00:grapi:1.4'
  1. Register your app at Goodreads

I recommend storing api key and secret at global gradle.properties file - this way you donโ€™t risk accidentally post it to git and its a common practice. This file usually can be found at your user home directory. [about global properties]. This is the way I do it at sample app. (donโ€™t mess it with local gradle.properties, which can be added to git)

  1. OAuth authorisation requires redirect, so you need to add this intent filter with your callback url, given from goodreads registration. (change host and scheme to your names - at sample app I used manifestPlaceholders for it)
<intent-filter>
    <action android:name="android.intent.action.VIEW"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <category android:name="android.intent.category.BROWSABLE"/>
    <data
            android:host="${host}"
            android:scheme="${scheme}"/>
</intent-filter>

Usage

Initialise before usage. (I donโ€™t keep reference to context, just using it for shared prefs, so donโ€™t be afraid of memory leaks)

grapi.init(this, BuildConfig.goodreadsKey, BuildConfig.goodreadsSecret, BuildConfig.goodreadsCallback)

OAuth:

Oauth flow:

  1. Call loginStart().
  2. Redirect to url from getAuthorizationUrl.
  3. After user returns back, loginEnd(intent) with given intent.
login.setOnClickListener {
    if (!grapi.isLoggedIn()) {
    	launch {
       	   grapi.loginStart()
           browse(grapi.getAuthorizationUrl())
        }
    } else {
       tryUseApi()
    }
}

the code below should be called from activity with previously added intent filter to catch redirect intent from browser

launch {
  grapi.loginEnd(intent) { ok ->
    if (ok) {
      // here we can start using api!
      tryUseApi()
    }
  }
}

and that's it for login. You can start making a requests to API. The sdk will keep access token at private shared prefs so you can just start using the api second time the user gets into your app.

Requests

launch {
    val userId = grapi.getUserId()
    val shelves = grapi.getUserShelves(1, userId.id)
    val reviews = grapi.getReviewList(
        userId.id,
        "read",
        1, 2,
        sort = Sort.NUM_PAGES,
        order = Order.DESCENDING
    )
    val book = grapi.getBookByISBN("837054150X")
    val book2 = grapi.getBookByGRID("13588846")
    val res = grapi.getSearchResults("Wiedลบmin")
    val user = grapi.getUser(userId.id)
    val allReviews = grapi.getAllReviews(userId.id, shelf = "favorites")
    // concurrent (~x2 faster) version of getAllReviews
    val allReviews2 = grapi.getAllReviewsConcurrent(userId.id, shelf = "favorites")
    val allShelves = grapi.getAllShelves(userId.id)
}

As you can see at sample app, Iโ€™m launching coroutines from ScoupedActivity context. Beware not to use requests methods from main thread.


coffee โ˜•๏ธ