Building a collection of Tech Blogs using React JS and HarperDB
Tags: javascript, tutorial, react, database
Published: 2022-03-30 18:34:12

As a developer or Technical Writer, what is the first thing you do when you run into an error or bug while coding?

You will probably Google the issue to see if someone else has faced a similar problem and solved it. If someone has found a solution to the problem they have encountered and has good writing skills, they will most likely write a blog post or an article explaining how they solved it.

As we all know, Google will only display blogs with Search Engine Optimization on the first page of search results. Unfortunately, there might be good blogs with a better solution to your problem, but you may never discover them.

For this reason, I want to show you how to create a dynamic web page with a collection of awesome blogs of your choice. In this case, you will learn how to create a collection of your favorite technical blogs over the internet based on these web development technologies.

- HTML
- CSS
- Javascript
- React

We will use React for the frontend and HarperDB as our database in this project. HarperDB is where all the dynamic data displayed on the front end will be stored. 

## What is HarperDB?

HarperDB is a SQL/NoSQL data management platform. In addition, HarperDB Studio, a web-based GUI where you can control and manage instances, will be used to handle data for this project.

You will then learn how to use HarperDB’s Custom Functions to create API endpoints that will help us to make an API request to a standalone API server inside HarperDB. The API request will get the dynamic blogs data stored in HarperDB, and then React will display it on the frontend.

In the end, you will learn how to create something, as shown below. 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rzgn74hhwyjf500vh4ph.jpg)

## Setting up a HarperDB Account 
Step 1: Start by creating your HarperDB Studio account. It's completely free to use, so sign up here: [studio.harperdb.io ](https://studio.harperdb.io/sign-up/)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u2yfrtihrv869b1k8vxv.png)

## Creating Your First Cloud Instance
Step 2: Now select "Create New HarperDB Cloud Instance," which will be used for this project. 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/clg0yf30nmzf0oazkka6.png)

Step 3: Select the Instance type. We'll use the cloud instance in this case.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fhg8rohwc3vuh41sku3t.png)

Step 4: Fill out the Instance details as per your preferences:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r4g83gjc5bur4isjs04l.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v388yiw3dfyjzava2sx2.png)

Step 5: After that, choose the specs. For the time being, we'll go with free options:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qcq87kxza8eau61u9hul.png)

Step 6: Your first cloud instance is successfully created! 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/06lmp8yaixwrpra6nehi.png)

It's time to populate the cloud instance with your own data.

## Creating Schema & Table data 

- Open the instance tech-blogs we just established.
- We need to develop a schema for our blog list data before we can add it.
- We will name our schema collection
- Name a table as blogs and save it. This will hold all of the data from the blog records that we require.
- Each record (here, blogs) will now require a hash_Attribute. Think of hash_Attribute as a "key."
- Name the hash_Attribute:  id


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l6ltn2pzxwii1adto5o1.png)

- In HarperDB, you can add queries (sql, nosql) as data, import a CSV, or just add a json object.
- We'll use a JSON object to store data in our app.

```json
[
    {
        "title": "Overreacted",
        "icon": "🔥",
        "description": "Dan Abramov writes about UI engineering, software development practices, and concepts in React.js",
        "tags": "react",
        "blog_url": "https://overreacted.io/",
        "twitter_url": "https://twitter.com/dan_abramov"
    },
    {
        "title": "Robin Wieruch's Blog",
        "icon": "☕",
        "description": "Robin writes guides and tutorials about React.js, Node.js, GraphQL and JavaScript. ",
        "tags": "javascript",
        "blog_url": "https://www.robinwieruch.de/blog/",
        "twitter_url": "https://twitter.com/rwieruch"
    },
    {
        "title": "Dave Ceddia's Blog",
        "icon": "⚛️",
        "description": "Dave's articles help you learn and master frontend development with React.",
        "tags": "react",
        "blog_url": "https://daveceddia.com/archives/",
        "twitter_url": "https://twitter.com/dceddia"
    },
    {
        "title": "Lee Robinson's Blog",
        "icon": "😄",
        "description": "He writes mostly about web development and tech careers.",
        "tags": "html",
        "blog_url": "https://leerob.io/blog",
        "twitter_url": "https://twitter.com/leeerob"
    },
    {
        "title": "Josh W. Comeau's Blog",
        "icon": "👋",
        "description": "He writes articles with a focus on React, Gatsby, CSS, and animation.",
        "tags": "react",
        "blog_url": "https://joshwcomeau.com/",
        "twitter_url": "https://twitter.com/JoshWComeau"
    },
    {
        "title": "CSS Tricks",
        "icon": "⭐",
        "description": "Daily articles about CSS, HTML, JavaScript, and all things related to web design and development.",
        "tags": "css",
        "blog_url": "https://css-tricks.com/",
        "twitter_url": "https://twitter.com/css"
    },
    {
        "title": "Smashing Magazine",
        "icon": "👊",
        "description": "Articles all around CSS, JavaScript, front-end, UX and design.",
        "tags": "css",
        "blog_url": "https://www.smashingmagazine.com/",
        "twitter_url": "https://twitter.com/smashingmag"
    }
]
```

- Let's use HarperDB Studio to add this data to our schema.
- Go to the blogs table and select the + icon:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uqfs993dzjx3ersh106z.png)

- It will open a blank page where you just need to paste the above JSON data as follows:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c36r4ojw29zky1n58wvi.png)

Save this data by clicking on the green button below. You will see the table like this: 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h2dt82cd4stcp7pcxvb0.png)

## Creating your first Custom Function with HarperDB Studio

### What are Custom Functions?
HarperDB introduced the concept of [Custom Functions](https://harperdb.io/docs/custom-functions/) in the 3.1+ release. They are customizable API endpoints that you can create and manage from within the HarperDB Studio.

- Now we have to create API endpoints to use in our app. Let's begin by making our first custom function.
- To access the functions option, go to the instance you created and select it from the navigation links:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ouqe5nkmsnnr6qj4jww4.png)

- Click on the Enable Custom Functions button and name the project as api.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wxkfo81e98iw07sjxj1y.png)

- You'll now be directed to a page where you can create routes and helper functions based on your app's requirements:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xievf19eqv77441x099v.png)

- Let's test the endpoint first. 

Replace the pre-written code in the ‘examples’ API routes file with the following:

```javascript
'use strict';

module.exports = async (server) => {

  server.route({
    url: '/',
    method: 'GET',
    handler: () => {
      return "A blogs API";
    }
  });
}
```
The URL is set to /, which can be accessed at {custom_functions_server_url}/{project_name}.

Your custom_functions_server_url can be found on the custom functions page, simply copy it:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9jgdmgianx6dh95q9y5p.png)

- Now open a new tab in your browser and test the endpoint: 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dux30nyqghlqajon960x.png)

- Great, it works perfectly!

## Setting up API endpoints

For now, this API does not fetch any blog data. This route will help us in developing an API endpoint to retrieve this information.

## Creating the API endpoint: 
 
```javascript
module.exports = async (server, { hdbCore, logger }) => {
 
	server.route({
	    url: '/blogs',
	    method: 'GET',
	    handler: (request) => {
	      logger.debug(request);
	      request.body= {
	        operation: 'sql',
	        sql: 'SELECT * FROM collection.blogs'
	      };
	      return hdbCore.requestWithoutAuthentication(request);
	    }
	  });
}
```

As you can see, we've changed the URL to /blogs this time. The handler function will make a SQL request which will return the blog's data.

Again, this route can be accessed at {custom_functions_server_url}/{project_name}/{url_route}


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/haaswxc1e1pnizwac87q.png)

We're getting the data from the blogs. Now let's make another endpoint that will display blogs according to tags:

```javascript
// GET blogs by tags
 
module.exports = async (server, { hdbCore, logger }) => {
 
	server.route({
	    url: '/blogs/:tags',
	    method: 'GET',
	    handler: (request) => {
	      logger.debug(request);
	      request.body= {
	        operation: 'sql',
	        sql: `SELECT * FROM collection.blogs WHERE tags LIKE '%${request.params.tags}%'`
 
	      };
	      return hdbCore.requestWithoutAuthentication(request);
	    }
	  });
}
```

> Because we've implemented a custom handler here, you must use prevalidation methods to avoid bypassing user authentication. Read more about it [here](https://harperdb.io/docs/custom-functions/define-routes/).

Testing our endpoint:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qcdqv5x7q05zq6y8s2yj.png)

The final route file is as follows:

```javascript
'use strict';

module.exports = async (server, { hdbCore, logger }) => {

	// GET blogs data
	server.route({
	    url: '/blogs',
	    method: 'GET',
	    handler: (request) => {
	      logger.debug(request);
	      request.body= {
	        operation: 'sql',
	        sql: 'SELECT * FROM collection.blogs'
	      };
	      return hdbCore.requestWithoutAuthentication(request);
	    }
	  });

	// GET blogs by tags	
	server.route({
	    url: '/blogs/:tags',
	    method: 'GET',
	    handler: (request) => {
	      logger.debug(request);
	      request.body= {
	        operation: 'sql',
	        sql: `SELECT * FROM collection.blogs WHERE tags LIKE             
                    '%${request.params.tags}%'`
 
	      };
	      return hdbCore.requestWithoutAuthentication(request);
	    }
	  });
}
```
Our API has been set up now. Let's make a project and put it into action.

## Designing The Frontend

Initialize the React app using create-react-app: 

```
npx create-react-app tech-blogs-harperdb
cd tech-blogs-harperdb
npm start
```

To begin, make a Header component for the Title and Description section:

```jsx
import "./Header.css";
const Header = () => {
    return (
        <div className="header">
            <h1>🔥Tech Blogs</h1>
            <p>
                A collection of amazing technical blogs found on web for
                developers.
            </p>
        </div>
    );
};
export default Header;
```

All the CSS files can be found here: [tech-blogs](https://github.com/ieshreya/tech-blogs-app) 

We've included a `Footer` component as well. You can find the code here:  [tech-blogs-github](https://github.com/ieshreya/tech-blogs-app/tree/master/src/components/Footer)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wj40h9lxarza89kcs247.png)

After that, make the card component. I'm going to call it BlogCard:
For now, all the values we're passing are hard-coded.

```jsx
import React from "react";
import "./BlogCard.css";

function BlogCard({ icon, title, description, twitter_url, blog_url, tags }) {
    return (
        <div>
            <div className="blogs-list">
                <div className="container">
                    <div className="card">
                        <div className="head">
                            <div className="icon">
                                <span>🚀</span>
                            </div>
                            <div className="title">
                                <h2>title</h2>
                            </div>
                        </div>
                        <div className="tags">
                            <p>react</p>
                        </div>
                        <div className="description">
                            <p>description</p>
                        </div>

                        <div className="flex-bottom">
                            <div className="social-icons">
                                <div className="twitter">
                                    <a href="#">
                                        <i className="fa-brands 
                                        fa-twitter"></i>
                                    </a>
                                </div>
                            </div>
                            <div className="visit-btn">
                                <a
                                    href="#"
                                    target="_blank"
                                    rel="noreferrer"
                                 >
                                    <button>Visit Blog</button>
                                </a>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    );
}

export default BlogCard;
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mutd3sohv1y1v54f910k.png)

This was all for the front-end.

It's time to put the API endpoints we developed in HarperDB Studio to work.

## Display All Blogs from API: 

Step 1: Create a file Blogs/Blogs.js under components folder: 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bf33nnq14amwap5v8wc8.png)

Step 2: Create a component called Blogs and initialize the states: 

```
import React, { useState, useEffect } from "react";
  
const Blogs = () => {
	const [isLoading, setIsLoading] = useState(true);
	const [blogs, setBlogs] = useState([]);
	}

export default Blogs;
```
Step 3: To fetch the blogs data from our API, initialize the useEffect method: 

> Your fetch url will be as follows: 
> {custom_functions_url}/{project_name}/{route_url}

```javascript
useEffect(() => {
        fetch("<CUSTOM_FUNCTIONS_URL>/api/blogs")
            .then((response) => response.json())
            .then((data) => {
                setBlogs(data);
                setIsLoading(false);
            });
    });
```
Step 4: Render the blog component: 

```jsx
return (
        <div className="blogs_data">
            <Header />
            <div>
                {isLoading ? (
                    <h2
                        style={{
                            display: "flex",
                            alignContent: "center",
                            justifyContent: "center",
                            padding: "5rem",
                        }}
                    >
                        Loading.. ⌛
                    </h2>
                ) : (
                    <div>
                        {blogs.map((blog) => {
                            return (
                                <BlogCard
                                    title={blog.title}
                                 description={blog.description}
                                    icon={blog.icon}
                                  twitter_url={blog.twitter_url}
                                    blog_url={blog.blog_url}
                                    tags={blog.tags}
                                />
                            );
                        })}
                    </div>
                )}
            </div>
        </div>
    );
```
Here's what our final Blogs component will look like:

```jsx
import React from "react";
import { useState, useEffect } from "react";
import "./Blogs.css";
import BlogCard from "../BlogCard/BlogCard";
const Blogs = () => {
    const [isLoading, setIsLoading] = useState(true);
    const [blogs, setBlogs] = useState([]);
    const [tags, setTags] = useState([]);
    useEffect(() => {
        fetch(
            `https://functions-tech-blogs-shreya.harperdbcloud.com/api/blogs/${tags}`
        )
            .then((res) => res.json())
            .then((data) => {
                setBlogs(data);
                setIsLoading(false);
            });
    }, [tags]);

    const allTags = ["HTML", "CSS", "JavaScript", "React"];
    function chooseTag(tag) {
        setTags(tag);
    }

    return (
        <div>
            {isLoading ? (
                <h2 className="loading_el">Loading.. ⌛</h2>
            ) : (
                <div>
                    <div className="nav_tags">
                        {allTags.map((tag) => {
                            return (
                                <div
                                    className="tags_el"
                                    onClick={() => chooseTag(tag)}
                                >
                                    <p>{tag}</p>
                                </div>
                            );
                        })}
                    </div>
                    <div>
                        {blogs.map((blog) => {
                            return (
                                <div>
                                    <BlogCard
                                        key={blog.id}
                                        title={blog.title}
                                        description={blog.description}
                                        icon={blog.icon}
                                        twitter_url={blog.twitter_url}
                                        blog_url={blog.blog_url}
                                        tags={blog.tags}
                                    />
                                </div>
                            );
                        })}
                    </div>
                </div>
            )}
        </div>
    );
};

export default Blogs;
```
Step 5: Congratulations! You've successfully used your first API endpoint:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3iqruz9421vc88v11qjb.gif)

Step 6: Now let's use the second endpoint which returns blogs according to tags requested from the route URL /blogs/:tags 

```jsx
const [tags, setTags] = useState([]);

useEffect(() => {
        fetch(
            `https://functions-tech-blogs-shreya.harperdbcloud.com/api/blogs/${tags}`
        )
            .then((res) => res.json())
            .then((data) => {
                setBlogs(data);
                setIsLoading(false);
            });
    }, [tags]);

    const allTags = ["HTML", "CSS", "JavaScript", "React"];

    function chooseTag(tag) {
        setTags(tag);
    }
```
Stage 7: We've set a dynamic routing as /${tags}. The function chooseTag will set the active tag for this route.

Updating the return method:

```jsx
return (
        <div>
            {isLoading ? (
                <h2 className="loading_el">Loading.. ⌛</h2>
            ) : (
                <div>
                    <div className="nav_tags">
                        {allTags.map((tag) => {
                            return (
                                <div
                                    className="tags_el"
                                    onClick={() => 
                                    chooseTag(tag)}
                                >
                                    <p>{tag}</p>
                                </div>
                            );
                        })}
                    </div>
                    <div>
                        {blogs.map((blog) => {
                            return (
                                <div>
                                    <BlogCard
                                        key={blog.id}
                                        title={blog.title}
                                  description={blog.description}
                                        icon={blog.icon}
                                  twitter_url={blog.twitter_url}
                                        blog_url={blog.blog_url}
                                        tags={blog.tags}
                                    />
                                </div>
                            );
                        })}
                    </div>
                </div>
            )}
        </div>
    );
```
Great! We can now view blogs by selecting categories too:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ejfu5x3302c6vm7g0q5t.gif)

That's it. You've used HarperDB Custom Functions successfully in your app.

## Conclusion

Now that you have learned how to build a collection of blogs, you can take this further and use HarpedBD and React to create a blog of your own. The best way to learn from tutorials is taking what you have learned and using it to build a project of your own. 

Building a project of your own will help you to take advantage of the HarperDB’s Custom Functions. HarperDB Studio is beginner friendly and their tutorials are direct to the point. Moreover, HarperDB is a better fit for projects where you need SQL and NoSQL, rapid application development, hybrid cloud, integration, edge computing and distributed computing.

Access the full code here: [tech-blogs-github](https://github.com/ieshreya/tech-blogs-app)
Visit Tech Blogs here: [tech-blogs.vercel.app](https://tech-blogs.vercel.app/)