Editor's Note: As of November 2024, this blog no longer reflects the reality of how the site's "currently reading" feature works. If you're curious about the how, you can skim this pull request. If you're curious about the why, you can read this blog post.
A couple weeks ago, on a lark, I decided to see if I could have the main landing page of this website dynamically update to reflect whatever book I'm currently reading.
Partly inspired by the fact that I started to use Oku - a neat little minimalist app, to track what I'm reading, want to read, and have read - and partly because I had some time between jobs and I needed a discrete little project to occupy myself for a day.
The resulting feature is a small one. I added an additional sentence in the copy of this site's landing page that will display any book I've marked within Oku as "currently reading."
I had basically three requirements for the feature:
Oku is built by a small engineering team and doesn't currently have any public facing APIs available to query directly. But they do have RSS feeds for any publicly viewable collection on their website. "Collection" is the app's term for an arbitrary grouping of books, either the defaults of "Read," "Want to Read," or "Currently Reading" or any collection made by a user (e.g. "Sitting on My Shelf and Staring at Me," "DNF", &c.).
My initial thought was to write some quick JavaScript to query the RSS feed directly, parse it, and update the landing page. However, the Oku team has good security practices and I wasn't able to do this because of cross-origin resource sharing (aka "CORS") restrictions. This was a minor setback, and also saved me from having to decide how I would parse the feed XML in the Browser.
Ultimately, the project's scope expanded ever so slightly and I ended up writing a lightweight API and hosting it as a Digital Ocean app.
Once api.cyberb.space
was up and running, adding the script to the page was pretty straightforward. Using the Fetch API, I query the API for my currently reading collection, I receive a JSON object in response, then I pull out the title and link data, slap some HTML on it, and update the contents of the .currently-reading
HTML element on my main page.
The flow ends up looking like this:
async function driver() {
fetch("https://api.cyberb.space/oku/rss/collection/SmX9F")
.then((response) => response.json())
.then((data) => extractTitlesAndLinks(data))
.then((titlesAndLinks) => formatTitles(titlesAndLinks))
.then((titlesHTML) => updateCurrentlyReadingSpan(titlesHTML));
}
Full code is available here. One fun little detail about this final implementation is that because of how lightweight I keep my website (no custom fonts, inline CSS, and a few other small design decisions). My full site loads fast enough that you can actually see when the JavaScript runs and the placeholder text is updated.
This was a fun little project. Did I learn anything new? Not really. But I do like seeing these titles updated with whatever I'm reading at given time.
I'm overdue for a redesign of the homepage and I have some ideas in mind. Regardless, I'll probably incorporate this little feature into whatever changes I make.
As a sort of post script, you should consider using Oku! It's nice and uncluttered and the team building it is adamant that they don't want to rely on ad-based revenue to keep it going, which is really refreshing in this day and age.