Everyone and their mothers always makes a goal to read more books at the start of every given year. Last year, I read more than I hoped, but on the previous version of my site had a tracker that was pretty tedious to use.
I want to display my book reading superiority so that everyone can see (a not-so-humble brag, if you will).
In the past I’ve used Goodreads to track all of my books. However, Goodreads deprecated their developer program a while back so if you don’t have an existing token you’re shit out of luck.
In my search for the perfect book tracker, I stumbled upon Literal. It’s like Goodreads, but their UI is from this century and they have an open GraphQL API. It’s like they knew I wanted to show off.
So after signing up, I imported my Goodreads library (looks like they’re one of the lucky ones with a live developer token 🤨) and got to work displaying my current read and favorites shelf on my site.
I’m using a Next.JS 13 app directory project, though I am sure most of the basic principles can slide over to any library.
I am using Apollo to query Literal’s API for client-sided queries. The first step to getting this up and running is to create a React Context that provides the Apollo client to the rest of the application.
Then, wrap it around your content in layout.tsx.
You may have noticed that I have a LITERAL_TOKEN and LITERAL_PROFILE_ID loading from my environment. To retrieve these, just POST to https://literal.club/graphql.
Grab the token and the profileId from the response and put those in your ENV file. To use client side in Next.JS, they need to be prefixed with NEXT_PUBLIC_.
For type info, you can define these models (and any other fields you want to use, full list here).
Once that is done, you can use useSuspenseQuery to query the API.
On the Server Side of things, I decided to just use asynchronous fetch (partially because I am not a frontend person, and I had trouble trying to use the Apollo client server side lol).
Because the Literal API has you retrieve read dates by a different query, I used this method to retrieve all read books, and combine the object with the read dates.
This returns a map, where the keys of the map are years and the content is an array of books.