--- title: "Managing my reading list" date: 2022-06-12T00:00:00 slug: 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](/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: ```json { "books": [ { "title": "Eyes of the Void", "author": "Adrian Tchaikovsky", "goodreads": "https://www.goodreads.com/book/show/58950674-eyes-of-the-void", "status": "completed", "completed_date": "25/05/22" }, { "title": "The Player of Games", "author": "Iain M. Banks", "goodreads": "https://www.goodreads.com/book/show/18630.The_Player_of_Games", "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](https://www.11ty.dev/docs/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](https://openlibrary.org) 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: ```javascript const getBook = async book => { const res = await axios.get(`https://openlibrary.org/search.json?author=${book.author}&title=${book.title}`); const key = res.data.docs[0].key; const work = (await axios.get(`https://openlibrary.org${key}`)).data; const cover = work.covers ? `https://covers.openlibrary.org/b/id/${work.covers[0]}-M.jpg` : undefined; return {...book, cover, "data": work }; }; module.exports = async function() { return await Promise.all(books.map(getBook)); } ``` ## 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: ```yaml layout: layout.njk pagination: data: readinglist size: 1 alias: book permalink: book/{{ book.title | slugify }}/index.html eleventyComputed: title: "{{ book.title }} - {{ book.author }}" --- ``` 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](/reading-list/), ~~or by viewing one of the information pages for a book, such as [Murder on the Orient Express](/book/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.