Back to blog

Managing my reading list

A little while ago I was toying with building a lightweight web app that would make it easy to manage and share reading lists. I never got around to making it, but instead I built a very-MVP version by adding my reading list to this website. It was a fairly simple construction, I simply added a file called reading-list.11tydata.json to my source directory, that looked like this:

    "books": [
            "title": "Eyes of the Void",
            "author": "Adrian Tchaikovsky",
            "goodreads": "",
            "status": "completed",
            "completed_date": "25/05/22"
            "title": "The Player of Games",
            "author": "Iain M. Banks",
            "goodreads": "",
            "status": "started"

Then, on my reading list page I could simply iterate over the books variable and output the data however I pleased. And it worked absolutely fine.

But it was't quite what I wanted, it doesn't give any information about the books I'm reading, e.g. if I wanted to add book covers I'd have to upload them manually. So, last night, when I really should have been sleeping, I started working on using data files, combined with using pagination to construct pages from data, to build something that was slightly closer to my original ambition.

Getting information about a book

Choosing a data source was pretty easy. Open Library has a very simple route-based API that would allow me to do all the things I needed to: search for a book by author and title, get information about that book, and get the book covers.

I did all this in a data file inside the _data directory, called readinglist.js. I added my original list of books, and then for each book I use the API to first search for the book, and choose the first result, then I get more detailed information about the book using the Works API, and then finally I look for a cover if it exists. Here's all the code to do that:

const getBook = async book => {
        const res = await axios.get(`${}&title=${book.title}`);
        const key =[0].key;
        const work = (await axios.get(`${key}`)).data;
        const cover =  work.covers ? `${work.covers[0]}-M.jpg` : undefined;

        return {, cover, "data": work };

module.exports = async function() {
    return await Promise.all(;

Constructing pages from the data

Update: I removed this feature as it wasn't particularly valuable and was slowing the build down

Eleventy makes this incredibly easy. I just had to add some pagination rules to the front-matter data on a new template:

layout: layout.njk
    data: readinglist
    size: 1
    alias: book
permalink: book/{{ book.title  | slugify }}/index.html
    title: "{{ book.title }} - {{ }}"

Eleventy took care of the rest, and generated all of the pages. I did find that I had to specify the .html extension for the permalinks. If I left it out, Eleventy wouldn't generate a valid HTML page and instead navigating to it would download the file instead of displaying it in-browser.

The result

You can see the results for yourself on the reading list, or by viewing one of the information pages for a book, such as Murder on the Orient Express. Overall, I'm actually really happy with how it turned out. It's a step closer to the web app that I'd originally envisioned, but it only took a few hours to put together.

There are a few limitations: I can't fine-tune what version of the book the API returns without more work, and I've got no control over the descriptions provided. But, I think it's a fair compromise to achieve what I wanted.

Overall, this was a fun little late-night project to pick up. As usual, I love how easy Eleventy makes tasks like this.