And in Android Studio it's even more easy to understand since that little guy:Implementing OAuth flowHere we can finally implement all the needed OAuth steps:obtain requestTokenredirect the user to AuthorizationUrlwhen it returns (captured by our deep-link) — verify that user granted permissions (authorize == “0”) and obtain oauth_tokenand finally, obtain accessTokenFrom the app developer perspective, these methods could be called like this:The only trick here is to understand that during the OAuth login we’ll be entering this activity twice (and I also used anko browse helper).
Few hours of work and we are ready to make some requests!Data gatheringEven though GR has some documentation about the data format, the design of such structures often seems quite unreasonable.
For example, the whole data is oriented around reviews and not around books.
I could probably write an entire topic just about API flaws, but instead, try to focus on data gathering: after you’ll get all the data you are free to transform it into more reasonable structures.
With kotlin data classes, it’s easy and compact to declare all the needed structures in just one file:Almost any of those fields could be absent.
I was guided by the rule that for strings the missed values equals to an empty string and for integers, it’s not the same as 0, so they can be null.
So now what is left is to parse this mess.
Another surprise — all the responses are in XML instead of JSON (some guy at dev forum even suggest GR team hire him, so that he could implement JSON endpoints).
I could not force any of the existed XML mappers to deal with such data, so eventually, I’ve implemented parsing by hands, according to this tutorial from Google.
I feel that it’s a good idea to implement DI pattern for parsers, in order to call them in such manner:parse<SearchResults>(xml)parse<UserShelves>(xml)parse<Book>(xml)That way we always call the same one method with the desired result type.
In kotlin DI could be done like this:We need to use a reified qualifier in order to access a type passed to us as a parameter (to use it in when expression).
The rest of the monotonous work is in different sets of parsers and readers.
The structure follows the google tutorial mentioned before and you could find details on GitHub (files: XMLReader.
Another few sleepless nights and you can do something like this in your app:JitPackI deployed my code to jitPack so that anyone who is interested in playing with GR data could use it.
There are many good tutorials out there about pushing your library to jitPack or maven, like this one.
The only problem I faced with was that when you are declaring some properties at your own global gradle file, jitPack remote servers don’t have it and so the build crashes.
To solve that — add these lines into your LOCAL gradle properties file:goodreadsKey=""goodreadsSecret=""If you do have a global config — it will override the local one.
But if no (like at jitPack servers), the keys still be available for gradle to use from BuildConfig and the app will build successfully.
ConclusionsAll the sources, link to the library, sample app and usage you could find here:intmainreturn00/grapiGoodreads unofficial android SDK ????.
Contribute to intmainreturn00/grapi development by creating an account on GitHub.
comI’ve added a few handy methods and also the library is tracking the login state via SharedPreferences now.
I wanted to take a pause here, before finishing the support for all the data structures GR provides.
My unofficial GR SDK covers probably the most interesting stuff already (user profile reviews, books, different searches, authors…), but I was wonder what functionality someone would need in addition to that.
I wonder if anyone else is interested in this library.
I strongly believe that GR data could be valuable for some awesome visualization and research, despite the problems with the format and API itself.
So, RFC!.Pull requests and comments are welcome.
And in the next article, I’ll show you how I used Google Sceneform and ARCore to visualize all my books in Augmented Reality to make some fancy Instagram photos!.