< All Blog

How Books page is Built

November 06, 2022

As I wrote in this blog, I created the Books page to list the books I have ever read. In this blog post, I'll explain how this page is built.

Data Model

At first I decided how to describe each Book models. As for the requirements, each book has basic information like title and authors. However, I'm not building Amazon. I don't need Book's product information like ISBN or published_at. Instead, since this is my private history of books I've read, I want to have read_at showing which year I finished reading that book.

In pseudocode, the data model looks like the following:

struct Book {
    authors: Author[];
    lang: String;
    read_at: Int;
    status: String;
    tags: Tag[];
}

struct Author {
    name: String;
    url: String;
}

struct Tag {
    value: String;
}

How to populate data

This site uses Gatsby as a framework for Static Site Generation (SSG). Gatsby has a concept of Transformer plugins, which is a pluggable architecture to stream and transform any data provided into nodes that can be queried via GraphQL during build steps.

JSON is apparently one of the most simplest data protocol to store books information. There is a gatsby-transformer-json plugin that works nicely to ingest and transform JSON into nodes that Gatsby can understand.

However, I want to have flexibility to manupulate books information. For example, some books have same authors. Tags can be used to group books, too. If I started editing those books with pure JSON, it'll be messy for renaming and refactoring data. I cannot put any source code comments into JSON.

This is where Jsonnet, a templating language for generating JSON, comes in.

Actual books.jsonnet now looks like as follows:

locals authors = {
    alice: {
        name: 'Alice',
        url: 'https://alice.example.com',
    },
};

locals tags = {
    programming: {
        value: 'programming',
    },
};

locals status = {
    reading: 'reading',
    completed: 'completed',
    todo: 'todo',
};

locals lang = {
    en: 'en',
    ja: 'ja',
};

// books
[
    {
        authors: [
            authors.alice,
        ],
        lang: lang.en,
        status: status.reading,
        read_at: 2022,
        tags: [
            tags.programming,
        ],
        title: 'Hacking Gatsby and React.js',
    }
]

How to query data

In order to make the data available as nodes in Gatsby, I need three steps to implement:

  1. Generate books.json from books.jsonnet
  2. Use gatsby-source-filesystem to read that books.json
  3. Use gatsby-transformer-json to transform JSON data into nodes

At first, generate books.json from the jsonnet file:

$ jsonnet "jsonnet/books.jsonnet" > "content/data/json/books.json"

Then, configure Gatsby to use two plugins:

// gatsby-config.js
module.exports = {
    plugins: [
        'gatsby-transformer-json',
        {
            resolve: 'gatsby-source-filesystem',
            options: {
                name: 'json',
                path: `${__dirname}/content/json`,
            },
        },
    ]
}

Now that data is transformed into nodes. The data can be queried via GraphQL as follows:

query {
    allBooksJson {
        edges {
            node {
                title
                id
                lang
                read_at
                status
                authors {
                    name
                    url
                }
                tags {
                    value
                }
            }
        }
    }
}

How to build the Books page

Finally a new file is created at pages/books.js with page query and decorated fetched GraphQL result with React.js components.

import React from "react"
import { graphql } from "gatsby"

const Bookshelf = ({
  data: {
    allBooksJson: {
      edges: allBooks
    },
  },
}) => {
    console.log(allBooks)
    returin //... use the GraphQL result to build the page!
}

export default Bookshelf

export const pageQuery = graphql`
  query {
    allBooksJson {
      edges {
        node {
          title
          id
          lang
          read_at
          status
          authors {
            name
          }
          tags {
            value
          }
        }
      }
    }
  }
`

Summary

Gatbsy abstracts the way data is transformed using the plugrable architecture. Thanks to this, Gatsby allow developers to build and populate data with flexibility, which is one thing I like about Gatsby.

Recommended Posts

  1. How to Toggle Header on Scroll with React.js

    October 18, 2022
    This blog post explains how I implemented togglable header in React.js. Behaviour The following shows how the header gets toggled as users scroll the pages: th…