Build a blog with a JSON server
Tags: javascript, beginners, programming, json
Published: 2022-05-10 12:34:57

## A quick development demo using JSON server
> _This tutorial is meant for those with some knowledge of Javascript and html._
> The purpose of building this blog is to write down the detailed operation history and my memo for learning the Js.
> If you are also interested and want to get hands dirty, just follow these steps below and have fun!~


### Prerequisites
- VS code with **Live Server** (Using VScode Extensions)
- node.js


## Getting Started

Download the starter project for this demo: [DemoBlog](https://github.com/hyc0812/json-server-starter)

Install the JSON server globally:
```js
npm install -g json-server
```

Create a folder named **data** in the starter project root directory and create a file named db.json inside the folder.

Copy and paste the following content into file **db.json**.
```json
{
    "posts":[
        {
            "id":1,
            "title":"Welcome to the new blog",
            "body":"Book description: In June, 1954, eighteen-year-old Emmett Watson is driven home to Nebraska by the warden of the juvenile work farm where he has just served fifteen months for involuntary manslaughter. His mother long gone, his father recently deceased, and the family farm foreclosed upon by the bank, Emmett's intention is to pick up his eight-year-old brother, Billy, and head to California where they can start their lives anew. But when the warden drives away, Emmett discovers that two friends from the work farm have hidden themselves in the trunk of the warden's car. Together, they have hatched an altogether different plan for Emmett's future, one that will take them all on a fateful journey in the opposite direction—to the City of New York.",
            "likes":30
        },
        {
            "id":2,
            "title":"How to be a good programmer",
            "body":"Book description: In June, 1954, eighteen-year-old Emmett Watson is driven home to Nebraska by the warden of the juvenile work farm where he has just served fifteen months for involuntary manslaughter. His mother long gone, his father recently deceased, and the family farm foreclosed upon by the bank, Emmett's intention is to pick up his eight-year-old brother, Billy, and head to California where they can start their lives anew. But when the warden drives away, Emmett discovers that two friends from the work farm have hidden themselves in the trunk of the warden's car. Together, they have hatched an altogether different plan for Emmett's future, one that will take them all on a fateful journey in the opposite direction—to the City of New York.",
            "likes":20
        },
        {
            "id":3,
            "title":"How to delete a post",
            "body":"Book description: In June, 1954, eighteen-year-old Emmett Watson is driven home to Nebraska by the warden of the juvenile work farm where he has just served fifteen months for involuntary manslaughter. His mother long gone, his father recently deceased, and the family farm foreclosed upon by the bank, Emmett's intention is to pick up his eight-year-old brother, Billy, and head to California where they can start their lives anew. But when the warden drives away, Emmett discovers that two friends from the work farm have hidden themselves in the trunk of the warden's car. Together, they have hatched an altogether different plan for Emmett's future, one that will take them all on a fateful journey in the opposite direction—to the City of New York.",
            "likes":31
        },
        {
            "id":4,
            "title":"This is the end of the world",
            "body":"Book description: In June, 1954, eighteen-year-old Emmett Watson is driven home to Nebraska by the warden of the juvenile work farm where he has just served fifteen months for involuntary manslaughter. His mother long gone, his father recently deceased, and the family farm foreclosed upon by the bank, Emmett's intention is to pick up his eight-year-old brother, Billy, and head to California where they can start their lives anew. But when the warden drives away, Emmett discovers that two friends from the work farm have hidden themselves in the trunk of the warden's car. Together, they have hatched an altogether different plan for Emmett's future, one that will take them all on a fateful journey in the opposite direction—to the City of New York.",
            "likes":15
        }
    ]
}
```

Run the JSON server at the root directory of this project:
```linux
json-server --watch data/db.json
```
> _This command will prompt json server to watch the json file db.json and give us access to API endpoints to interact with resources in this json file._

The output message might be like the following:
```linux
  \{^_^}/ hi!

  Loading data/db.json
  Done

  Resources
  http://localhost:3000/posts

  Home
  http://localhost:3000

  Type s + enter at any time to create a snapshot of the database
  Watching...
```
Now right click **index.html** in the project root directory and select **Open with Live Server**, and we should see the resources using **inspect**:

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


Update the following content to the **js/create.js** file:
```js
// javascript for create.html
const form = document.querySelector('form');
const createPost = async (e) => {
    e.preventDefault();
    const doc = {
        title: form.title.value,
        body: form.body.value,
        likes: 10
    }
    await fetch('http://localhost:3000/posts', {
        method: 'POST',
        body: JSON.stringify(doc),
        headers: { 'Content-Type': 'application/json' }
    });
    window.location.replace('/index.html');
}
form.addEventListener('submit', createPost);
```
Update the following content to the **js/detail.js** file:
```js
// javascript for details.html
const id = new URLSearchParams(window.location.search).get('id');
const container = document.querySelector('.details');
const deleteBtn = document.querySelector('.delete');

const renderDetails = async () => {
    const res = await fetch(`http://localhost:3000/posts/${id}`);
    const post = await res.json();
    
    const template = `
        <h1>${post.title}</h1>
        <p>${post.body}</p>
        `
    container.innerHTML = template;
}
deleteBtn.addEventListener('click', async (e) => {
    e.preventDefault();
    await fetch(`http://localhost:3000/posts/${id}`, {
        method: 'DELETE'
    });
    window.location.replace('/index.html');
})
window.addEventListener('DOMContentLoaded', () => renderDetails());
```
Update the following content to the **js/index.js** file:
```js
// javascript for index.html
const container = document.querySelector('.blogs');
const searchForm = document.querySelector('.search');

const renderPosts = async (term) => {
    let uri = 'http://localhost:3000/posts?_sort=likes&_order=desc';
    if (term) {
        uri += `&q=${term}`;
    }
    const res = await fetch(uri);
    const posts = await res.json();
    let template = '';
    posts.forEach(post => {
        template += `
            <div class="post">
                <h1>${post.title}</h1>
                <p><small>${post.likes} likes</small></p>
                <p>${post.body.slice(0, 200)}</p>
                <a href="/details.html?id=${ post.id }">Read more...</a>
            </div>
        `
    })
    container.innerHTML = template;
}
searchForm.addEventListener('submit', e => {
    e.preventDefault();
    renderPosts(searchForm.term.value.trim())
})
window.addEventListener('DOMContentLoaded', () => renderPosts());
```

Update the following content to the **create.html** file:
```html
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="styles.css">
  <title>JSON Server</title>
</head>
<body>
  <h1>Create a New Blog</h1>
  <form>
    <input type="text" name="title" required placeholder="Blog title">
    <textarea name="body" required placeholder="Blog body"></textarea>
    <button>Create</button>
  </form>
  <script src="js/create.js"></script>
</body>
</html>
```
Update the following content to the **detail.html** file:
```html
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="styles.css">
  <title>JSON Server</title>
</head>
<body>
  <div class="details">
    <!-- inject blog details here -->
  </div>
  <button class="delete">Delete</button>
  <script src="js/details.js"></script>
</body>
</html>
```
Update the following content to the **index.html** file:
```html
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="styles.css">
  <title>JSON Server</title>
</head>
<body>
  <nav>
    <h1>All Blogs</h1>
    <a href="/create.html">Add a new blog</a>
  </nav>
  <form class="search">
    <input type="text" name="term" placeholder="search term">
    <button type="submit">Search</button>
  </form>
  <div class="blogs">
    <!-- inject blogs here from js -->
  </div>
  <script src="js/index.js"></script>
</body>
</html>
```
Update the following content to the **styles.css** file:
```css
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap');

/* base styles */
body {
  background: #eee;
  font-family: 'Roboto';
  color: #444;
  max-width: 960px;
  margin: 100px auto;
  padding: 10px;
}
nav {
  display: flex;
  justify-content: space-between;
}
nav h1 {
  margin: 0;
}
nav a {
  color: white;
  text-decoration: none;
  background: #36cca2;
  padding: 10px;
  border-radius: 10px;
}
form {
  max-width: 500px;
}
form input {
  width: 100%;
}
input, textarea {
  display: block;
  margin: 16px 0;
  padding: 6px 10px;
  width: 100%;
  border: 1px solid #ddd;
  font-family: 'Roboto';
}
textarea {
  min-height:200px;
}
/* post list */
.post {
  padding: 16px;
  background: white;
  border-radius: 10px;
  margin: 20px 0;
}
.post h2 {
  margin: 0;
}
.post p {
  margin-top: 0;
}
.post a {
  color: #36cca2;
}
```
Now we can interact with the JSON server using this project:
Right click **index.html** in the project root directory and select **Open with Live Server**, and we should now see the following:

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


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


### Reference
https://www.youtube.com/watch?v=VF3TI4Pj_kM&list=PL4cUxeGkcC9i2v2ZqJgydXIcRq_ZizIdD&index=2
https://www.npmjs.com/package/json-server

### Final Example Code
[DemoBlog](https://github.com/hyc0812/json-server-final-version)