DEV Community

Cover image for Build a blog with a JSON server
Yongchang He
Yongchang He

Posted on

Build a blog with a JSON server

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

Install the JSON server globally:



npm install -g json-server


Enter fullscreen mode Exit fullscreen mode

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.



{
    "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
        }
    ]
}


Enter fullscreen mode Exit fullscreen mode

Run the JSON server at the root directory of this project:



json-server --watch data/db.json


Enter fullscreen mode Exit fullscreen mode

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:



  \{^_^}/ 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...


Enter fullscreen mode Exit fullscreen mode

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

Update the following content to the js/create.js file:



// 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);


Enter fullscreen mode Exit fullscreen mode

Update the following content to the js/detail.js file:



// 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());


Enter fullscreen mode Exit fullscreen mode

Update the following content to the js/index.js file:



// 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());


Enter fullscreen mode Exit fullscreen mode

Update the following content to the create.html file:



<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>


Enter fullscreen mode Exit fullscreen mode

Update the following content to the detail.html file:



<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>


Enter fullscreen mode Exit fullscreen mode

Update the following content to the index.html file:



<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>


Enter fullscreen mode Exit fullscreen mode

Update the following content to the styles.css file:



@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;
}


Enter fullscreen mode Exit fullscreen mode

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

Image description

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

Top comments (9)

Collapse
 
prudence97 profile image
Prudence97

Helloooo

Do you have any resource that can help me add images on my db.json.

I read it follows a different procedure but I'm not getting sufficient help online

Collapse
 
yongchanghe profile image
Yongchang He

Hello there,

Thank you for your message!
I don't have such experience previously. I googled this question and not sure if this could help solve your problem:LINK. Thank your and have a good night.
Cheers!

Collapse
 
prudence97 profile image
Prudence97

Thank you. I found this commentโ†“

The JSON format can contain only those types of value:

  1. string
  2. number
  3. object
  4. array
  5. true
  6. false
  7. null

An image is of the type "binary" which is none of those. So you can't directly insert an image into JSON. What you can do is convert the image to a textual representation which can then be used as a normal string.

The most common way to achieve that is with what's called base64. Basically, instead of encoding it as 1 and 0s, it uses a range of 64 characters which makes the textual representation of it more compact. So for example the number '64' in binary is represented as 1000000, while in base64 it's simply one character: =.

There are many ways to encode your image in base64 depending on if you want to do it in the browser or not.

Note that if you're developing a web application, it will be way more efficient to store images separately in binary form, and store paths to those images in your JSON or elsewhere. That also allows your client's browser to cache the images.

edited Nov 28, 2018 at 11:26
answered Dec 27, 2015 at 22:27

lleaff

Thread Thread
 
prudence97 profile image
Prudence97

It think it means that I'll either have to convert it to binary ๐Ÿ™‡โ€โ™€๏ธbut converting it makes it larger.

I also found another one. I'll send it to you

Thread Thread
 
prudence97 profile image
Prudence97

Ken Alger
on Dec 28, 2015

It depends upon your application, storage system, etc. But let's just make up an example of needing to store company logos in a database to display on our website, obviously could be for a multitude of other reasons but that's what we'll run with.

{
"ebay" : {
"type": "online auction site",
"logoLocation": "../img/corporate/ebay.svg"
},
"treehouse" : {
"type": "online learning site",
"logoLocation": "../img/corporate/treehouse.jpg"
},
"lawnmower" : {
"type": "household gardening",
"logoLocation": "../img/personal/lawnmower.png"
}
}

You then should be able to easily navigate to lawnmower.logoLocation in your application language, get the file path, and display it. That part will largely depend on the language in particular and how your .json file is being generated, stored, and maintained.

You could also embed base64 images instead of the logoLocation field but that obviously increases file size greatly.

Hope that helps in some fashion.

Happy coding,
Ken

Thread Thread
 
prudence97 profile image
Prudence97

I don't know how the second one works. I guess I'll have to try it๐Ÿ™‡โ€โ™€๏ธ๐Ÿ™‡โ€โ™€๏ธ

I was considering using Supabase in the end.

๐Ÿคท Because how would I manage large images if I have to do this.

Also how do I add this to the a particular id

Thread Thread
 
yongchanghe profile image
Yongchang He

Hello,

Thank you for your message!

I saw you are learning React, and that's easy for you to show your pics using the second way you were described using React.

In the public folder you can add a directory assets/images, and then place all the images that you want to show in the front end, and you can display these images by using <img src="assets/images/YOUR_IMAGE.png" alt="" className="YOUR_CLASS_NAME"/> in some of your Component.js.

This is my mini demo which may help(see project-2 / project-4) Link.

This tutorial (for learning React) is the original resource for building the projects above. I think you can learn it step by step if you are available.

Cheers!

Collapse
 
summerislandfun profile image
bob • Edited

how can we add pagination to this? Otherwise there are like 50 posts loading at once after a while. I know you can add ?_page=1&_limit=5 or something. but how do i add the new page or infinite scroll?

Super awesome guide! thanks a lot

Collapse
 
summerislandfun profile image
bob

follow up question, if i make the site live. how do i make sure it watches the correct file? i can't do a json-server --watch command on the website