Create a serverless book library app with HarperDB and Gatsbyjs
Tapas Adhikary
Posted on June 15, 2021
One of the many advantages of trying out side-projects is, you never run out of the ideas of trying out something new. For example, recently, I had an opportunity to try out a modern, easy-to-use, fast database, HarperDB. As I learned how to set up and use it, I could further explore building a serverless app using it.
This article will learn how to create a serverless book library app using HarperDB and Gatsbyjs. We will also learn to deploy the app on the Gatsby Cloud. I hope you enjoy following along and build the app with me.
So, What are we going to learn?
We will learn to,
Setting up HarperDB.
Configure the Schema and Table in HarperDB.
Populate data in HarperDB.
Setting up a Gatsbyjs project.
Use a Gatsbyjs Plugin to access HarperDB data at the build time.
Build the user interfaces for the book library app. It's all with Reactjs.
Deploy the app on the Gatsby Cloud to access it publicly.
At any point in time, feel free to refer to the source code of the app from the GitHub repository,
Flicks is a project to showcase the integration between Gatsbyjs and HarperDB. It provides a Gatsby-based user interface pulling data from the HarperDB. So you can assume it to be a library showing information about my favorite books!
Flicks - Know My Favorite Books
Flicks is a project to showcase the integration between Gatsbyjs and HarperDB. It provides a Gatsby-based user interface pulling data from the HarperDB. So you can assume it to be a library showing information about my favorite books!
Please feel free to fork and change the project in whatever ways you need to. If you like the work, please show your support by giving the repo a star(⭐)
Many Thanks to all the Stargazers who has supported this project with stars(⭐)
You must have Node.js installed. Please make sure you have installed Node.js version >= 12.13.0. You can download and install Node.js from here. You can check the version of the existing Node.js installation using the command, node -v.
Knowledge of Reactjs would be helpful as Gatsbyjs is React-based.
Before we begin, What is serverless anyway?
There is a high chance that you may have a couple of doubts as I had about the term serverless.
Does serverless mean there are no servers involved at all in the app development?
Nope, both of them are not true in the context of this article. A server exists to provide services. It could be e-mail, form, hosting, and even database. By serverless it doesn't mean there are no servers involved in the app development. It instead means we as developers do not set up, manage, and maintain these servers. Instead, we leverage the services made available and managed by providers like Google, Amazon, Netlify, Vercel, Gatsby, HarperDB, and many more.
Coming to the second point above, the Serverless Framework is a service that helps us to go serverless. However, we will not use it in this article.
HarperDB
HarperDB is a fast, flexible database that allows you to perform rapid application development, distributed computing, SaaS, and many more. To set up HarperDB in a serverless way, we need to configure a cloud instance. But the first thing first, let's create an account with HarperDB.
Setting Up HarperDB
Please browse to https://harperdb.io/ and create an account for free. Please click on the link Start Free as shown below. If you have an account already, please sign in using this link, https://studio.harperdb.io/
Figure 1.1: Create a Free Account
As part of the signup process, you need to provide the details like name, email, subdomain name. HarperDB will now create a subdomain for you. So please provide the details and sign up for free.
Figure 1.2: Specify Details to Sign Up
In the next step, you need to provide an account password. Please provide a strong password and complete the account creation process.
Figure 1.3: Specify the Account Password
Now, let's create a HarperDB cloud instance. We will use this cloud instance to create and fetch data for our application. Please click on the section Create New HarperDB Cloud Instance to move to the next step.
Figure 1.4: Create a HarperDB Cloud Instance
Next, please select the Create HarperDB Cloud Instance as shown in the image below.
Figure 1.5: Create HarperDB Cloud Instance
Now we have to specify the cloud instance name and credentials. Please provide an instance name of your choice along with the credentials.
Figure 1.6: Specify Instance Name and Credentials.
Next, you need to select the RAM size, storage size, and other spec details. Please select all the free options.
Figure 1.7: Select the specs
The last step is to confirm and add the HarperDB cloud instance. Again, please review the details and click the Add Instance button.
Figure 1.8: Review the instance details and Add
You should see the instance creation getting started.
Figure 1.9: Creating Instance is In-Progress
It may take a few minutes. However, you should see the status as OK after a successful HarperDB cloud instance creation.
Figure 1.10: Status OK
A final step. Please go to the config tab and copy the API Auth Header Key. Please preserve it somewhere, as we will use it when we configure Gatsbyjs with HarperDB.
Figure 1.11: HarperDB API Auth Header Key
That's all. We have successfully created a HarperDB cloud instance that is ready to use.
Configure the Schema and Table
We need to create a schema and table to insert a few records into the DB. To do that, load the HarperDB cloud instance from the dashboard. First, create a schema by specifying a schema name. For our app, let's give a schema name as library.
Figure 2.1: Create a Schema
Next, let's specify a table name. Let's specify book as the table name and create. Please note, you have to specify a hash_attribute for the table. HarperDB will auto-generate the value for it. You may manually add it if you want to specify its value. In our case, we will let HarperDB create it. Let's specify the id column as the hash_attribute for the book table.
Figure 2.2: Create a Table
Populate data in HarperDB
We will now populate data in HarperDB. We will insert a few records of books into the book table using the HarperDB user interface. You can insert one record by specifying a JSON object or multiple records at once by specifying an array of JSON objects. Let us create a book record by specifying these properties and values,
{author:['Kyle Simpson'],cover:'https://res.cloudinary.com/atapas/image/upload/v1622356611/book-covers/you_dont_know_js_1_le1xk5.jpg',description:'No matter how much experience you have with JavaScript, odds are you don’t fully understand the language. As part of the series, this compact guide focuses on new features available in ECMAScript 6 (ES6), the latest version of the standard upon which JavaScript is built.',isbn:9781491904244,pages:278,published:'2015-12-27T00:00:00.000Z',publisher:'O\'Reilly Media',rating:5,subtitle:'ES6 & Beyond. It covers all aspects of javaScript deep down.',title:'You Don\'t Know JS',topic:'JavaScript',website:'https://github.com/getify/You-Dont-Know-JS/tree/master/es6%20&%20beyond'}
Click on the save icon to save the record.
Figure 3.1: Insert a book record
Similarly, you can insert multiple records. So please insert a few more records as the book library must contain more than just one book!
Figure 3.2: Book Records
You can make use of the JSON data from my GitHub Repository to create multiple records.
Congratulations 🎉 !!! You have completed the database setup with the required data. Now, we will move our focus towards building the User Interface for the book library app.
Gatsbyjs(aka Gatsby)
Gatsby is a React-based framework that allows you to build fast, secure, and robust websites. You can create markups with data at the build time and deploy the built artifacts to serve your pages much faster. It gives a phenomenal performance and speed improvement over the traditional client-server model. We will use Gatsby to create prebuilt markups using the data record added to the HarperDB.
Gatsby Plugin for HarperDB
Gatsby's massive plugin ecosystem allows us to pull data from several data sources, avail themes, and many more use-cases. Unfortunately, I couldn't find any existing Gatsby plugin for the HarperDB data source. But, as they say, necessity is the mother and all inventions, I thought of creating one!
So now we have a Gatsby Plugin for HarperDB (gatsby-source-harperdb) that allows you to use the HarperDB as the data source so that a Gatsby project can pull the data at the build time. You can find the source code of the plugin from here,
It is also available as an official plugin to install from the Gatsby's plugin page. So please give it a try.
Setting up a Gatsby Project
Alright, it's time to create our gatsby project. First, install the gatsby command-line interface(CLI) tool. Open a command prompt and use this command to install it globally,
npm install gatsby-cli -g
We will use the latest gatsby version 3.x to bootstrap our project. Gatsby provides many starter projects to get started with the development faster. Now let's create a gatsby project. Try this command from the command prompt,
gatsby new
It will ask you a few questions like the site name, what kind of CSS library support you need, what are plugins you want to install? The image below shows my answers. You can choose to go with the same or anything else suitable for you.
Figure 4.1: Creating a Gatsby Project
Please give it a while to complete the installation and set up the project for you. Once done, you should see a folder created with the site name provided by you in the last step. For me, it is flicks. Please change to the project directory and try this command from the command line,
gatsby develop
It will run the project in the development mode. First, it will build the project and then host the prebuilt markups from a server locally to access the app. By default, the app will run on the URL, http://localhost:8000. Please open a browser window/tab and try the URL. You should see your app up and running,
Figure 4.2: The Initial App
Configure HarperDB with our Gatsby App
Let's configure the HarperDB with our Gatsby app. We will use the gatsby-source-harperdb plugin. Please install it using the following command,
npm install gatsby-source-harperdb
# If you are using yarn, try this,# yarn add gatsby-source-harperdb
Now create a file called .env at the root of the project folder. Please specify the API auth header key and the instance URL in the .env file.
Please replace the API_KEY_VALUE with the API auth header key we copied before. Also, replace the CLOUD_INSTANCE_VALUE with your cloud instance value. The URL ends with .harperdbcloud.com.
Please make sure you add an entry of .env in your .gitignore file. You may not want to commit and push this file to your GitHub repository.
We need to install the dotenv package to read environment variables from the .env file. You can install it using this command,
npm install dotenv
Now open the gatsby-config.js file at the root of the project folder. It is a file to configure all the gatsby plugins required for the project. You may find a few plugin entries already. We have installed those while creating the project. Add this line at the top of the gatsby-config.js file,
require('dotenv').config();
Next, please add the configuration for the gatsby-source-harperdb in the config file.
plugins:[....{resolve:`gatsby-source-harperdb`,options:{secret:process.env.HARPER_DB_SECRET_KEY,url:process.env.HARPER_DB_URL,payload:{"operation":"sql","sql":"SELECT * FROM library.book"},type:"books"},},],
Please note the options in the above configuration,
We read the API Key from the .env file and use it for the secret value.
Similarly, we get the HarperDB cloud instance URL from the .env file and use it in the configuration.
Next is the payload that we use to query HarperDB. Here we are specifying the SQL query to retrieve the data from the book table of the library schema.
Last, specify the value of the type property. It can be any string of your choice. It is the name under which your data will appear in Gatsby GraphQL queries. For example, if we specify books as the type name, Gatsby will create GraphQL queries as allBooks and books. We will see that in a while.
If you are running the gatsby develop already, please stop it(using the control + c key combination) and start again.
Fetch the Book records in the UI
Gatsby source plugins make the data available to query using GraphQL queries. In addition, it provides a GraphQL playground for us to try out the queries before we use them in the app. To Open the GraphQL playground and query the book data from the HarperDB, please open this URL in your browser tab: http://localhost:8000/___graphql. You should see the allBooks and books types under the explorer.
Figure 5.1: GraphQL Explorer
Now expand the allBooks type from the explorer. Then expand the nodes node and select the attributes to query. As you select, you will see the query is getting built automatically. Now, execute the query using the Execute Query button at the top. You will see the result of the query at the rightmost pane. Please refer to the image below.
Figure 5.2: GraphQL Query Execution
We will now use this query in our UI code(React components) to build the user interfaces.
Build the User Interfaces(UI)
Now we will build the user interfaces using this query to show the books in the UI. In the UI, we will first list all the books with details like title, topic, cover, author, subtitle. Then, when users click on any of the books, we take them to a details page to show more details about that book.
Create the Book Listing Page
Let us create the book listing page. Open the index.js file under the src/pages folder. Replace the content of the file with the following content,
// 1. Import React, Styled-Components, and gatsbyimport*asReactfrom"react";importstyledfrom"styled-components";import{useStaticQuery,graphql}from"gatsby";// 2. Create Styled ComponentsconstMain=styled.div`
display: flex;
flex-direction: column;
`;constContainer=styled.div`
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
`;constBook=styled.div`
border: 1px solid #4e4e4e;
border-radius: 4px;
padding: 0.5rem;
width: 250px;
min-height: 450px;
margin: 1rem;
`;constResponsiveImage=styled.img`
width: 100%;
height: auto;
`;constTitle=styled.span`
font-size: 20px;
font-weight: 500;
`;// 3. The IndexPage ComponentconstIndexPage=()=>{// 4. Query the data using GraphQL queryconstdata=useStaticQuery(graphql`
{
allBooks {
nodes {
title
id
author
cover
rating
subtitle
topic
}
}
}
`);constbooks=data.allBooks.nodes;books.sort((a,b)=>{returnb.rating-a.rating;});// 5. The Markup to render with the datareturn (<Main><Container>{books.map((book,index)=>(<Bookkey={index}>{book.topic}<div>{book.cover&&(<ResponsiveImagesrc={book.cover}alt={`${book.title}`}/>
)}</div>
<Title>{book.title}</Title> by{" "}
<span>{book.author.join(", ")}</span>
<p>{book.subtitle}</p>
<p>{book.rating}</p>
</Book>
))}</Container>
</Main>
);};exportdefaultIndexPage;
Let us go over the code above and understand. It is a regular React component where,
We import React, Styled-Components, and gatsby libraries.
Create Styled Components for the main page, container inside it, and each box to show the book information.
Then, we start the IndexPage component.
In the component, we use the GraphQL query to fetch the books data. We fetch only the required attributes for the listing page. Please notice we use the useStaticQuery hook from gatsby to perform the fetch. Gatsby recommends this hook to fetch data using the GarphQL queries inside a Gatsby component. We also sort the books based on the rating.
Last, we have the markup to render using the data.
Now refresh the page where the app is running. You will see a list of books with details like the image below,
Figure 5.2.1: The Book Listing Page
Create the Book Details Page
Great! Let us now implement the book details page. It will show a book's details when the user clicks on book information from the listing page. Gatsby provides a super cool feature of creating pages ahead in time(build time) using templates. So, we can create a single template for all the book details as we will show a similar structure for all the books.
Create a folder called templates under the src folder. Now create a file called BookDetails.js under src\templates with the following content.
We are doing the followings in the template code above,
Import all required libraries for the template to work.
Create Styled Components for UI structure to show the book details.
Then, we create the BookDetails React component and render the book details. Please note, we pass a prop to the component as { data }. It means we are performing destructuring here to extract the data from an object. But, from which object?
In a gatsby project, pages and templates use the result of a query as the prop. Please note the GraphQL query at the bottom of the source code. Here we are performing a filter query to filter out a book by its title. The result of this query will be passed automatically to the BookDetails component as a prop. We extract the data from that and use it for the rendering.
Now, as we have the template ready, we need to use it to create the pages for each of the books. Let's configure that.
Create a file called gatsby-node.js at the root of the project folder with the following content. It is a special file that helps in invoking Gatsby APIs and overrides them to customize things.
constpath=require(`path`);const_=require("lodash");exports.createPages=async ({graphql,actions})=>{const{createPage}=actions;constresult=awaitgraphql(`
query {
allBooks {
edges {
node {
title
}
}
}
}
`);result.data.allBooks.edges.forEach((edge)=>{createPage({path:`/${_.kebabCase(edge.node.title)}/`,component:path.resolve(`./src/templates/BookDetails.js`),context:{// Data passed to context is available// in page queries as GraphQL variables.title:edge.node.title,},});});};
Here we are using the createPages API of Gatsby to create pages based on the query. First, the query fetches all the book titles. Then, it creates a page using the template for each of the titles and passes the title as a context. Each page will be accessed using a unique URL we build with the path attribute. Also, if you recall, we use the title in the template to filter the book information.
Please note, we use the lodash library to utilize its method for formatting a URL fragment. Usually, a title may have spaces, and the URL doesn't accept that. So we use the _.kebabCase(edge.node.title) to replace the spaces with a hyphen(-) character. Please install lodash as a dependency.
npm install lodash
Now restart gatsby develop once more. Next time when the gatsby develop runs, it will create the pages for all the books using the template.
So let us now create a link from each of the books on the book listing page to its respective details page. Please open the index.js file. Include these two imports at the top,
// ... Other importsimport_from"lodash";import{Link}from"gatsby";
Then, wrap the <Book> tag using the Link like this,
Please note the to attribute of the Link. It links you to the URL fragment created using the title the same way we mapped the pages in the gatsby-node.js file. Save your changes and refresh the app in the browser. Now, you will be able to click on the books from the listing page. Click on a book, and you should land on a details page like the one shown below,
Figure 5.2.2: Book Details Page
That's it. We have the book library app ready with basic functionality. Please feel free to enhance the look and feel of the app using styles. You can add features like searching a book, filtering, many more.
Deploying on Gatsby Cloud
Welcome to the last section of the article. Now we will deploy the library app to the Gatsby Cloud with a few quick steps. At this stage, please create a repository on GitHub and push all the code.
Please Create an account with Gatsby Cloud and Log in. Please select the free build and hosting plans while creating the account. Next, click on the Add a site button.
Figure 6.1: Add a Site
Select the Import from a Git repository option and click on the Next button.
Figure 6.2: Select from a Git Repo
Assuming you have pushed your code to the GitHub repository, please select the GitHub option.
Figure 6.3: Select Repository Type
Please provide the repository details and the site name and got to the next step.
Figure 6.4: Provide Repository Details
We will not use any CMS for our application. Therefore, you can skip the step of selecting the CMS.
Figure 6.5: Skip CMS
In the last step, please provide the environment variable details and finish the setup.
Figure 6.6: Provide Environment Details
Now a build should get triggered automatically. Once the build is successful, the app will be available at https://<YOUR_SITE_NAME>.gatsbyjs.io. In my case, it is flicks.gatsbyjs.io.
Figure 6.7: Trigger Build
That's all. We have come to the end of this article. I hope you found it insightful. Thanks for reading and trying out. Please feel free to comment below with the link to your app. Also, feel free to reach out to me if you face any issues in following the article.
I hope you enjoyed this article or found it helpful. Let's connect. You can find me on Twitter(@tapasadhikary), sharing thoughts, tips, and code practices.