DEV Community

Cover image for Build a blog within 15 lines with Node.js and KeyVox
keyvox
keyvox

Posted on

Build a blog within 15 lines with Node.js and KeyVox

You want a blog on your website but you don't have time to build the entiere CMS.

KeyVox is a simple API to build a blog within 15 lines.

How does it works ?

There is nothing to install, nothing to configure.

4 steps:

  1. Create a blog in one clic
  2. Write your articles in our CMS
  3. Create an API key
  4. Fetch your content from our CMS

Image description

Simple example with Node.js and Express

Let's start a new project.

npm i express dotenv keyvox-node
Enter fullscreen mode Exit fullscreen mode

In this example, let's take this key (the API is read-only).
API_KEY="e5cd764a23bd72132a117756ed4ca0f1c1d1716b033eb479"

import KeyVox from 'keyvox-node';
import 'dotenv/config';
import express from 'express';
const kv = new KeyVox(process.env.API_KEY)
const app = express();
app.listen(process.env.APP_PORT)
Enter fullscreen mode Exit fullscreen mode

Fetch news articles

const articles = await kv.articles.list({
    page: 1,
    limit: 6
})
Enter fullscreen mode Exit fullscreen mode
{
  "data": [
    {
      "id": "2ae271b5-36b4-45e2-8a4a-7c95c38cde57",
      "title": "New NFT collection",
      "slug": "new-nft-collection",
      "status": "published",
      "meta": {},
      "background": "https://keyvox.dev/images/articles/2ae271b5-36b4-45e2-8a4a-7c95c38cde57/a00de3a7aed7a58c5b65a97a39a148c2c28fb187afa0.png",
      "tags": [
        {
          "title": "nft",
          "slug": "nft"
        },
        {
          "title": "defi",
          "slug": "defi"
        }
      ],
      "created_at": "2024-02-10T14:06:39.981Z",
      "updated_at": "2024-02-10T14:19:56.531Z"
    }
  ],
  "meta": {
    "url": "http://keyvox.dev/api/articles?",
    "count": 1,
    "pages": 1,
    "items_per_page": 9
  }
}
Enter fullscreen mode Exit fullscreen mode

Then return a view as response.

app.get(async (req, res) => {
    const articles = await kv.articles.list({ page:1, limit: 6 });
    res.render('index.html', articles);
})
Enter fullscreen mode Exit fullscreen mode

The html returned is a classical loop (we use Tailwindcss in the example).

<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-200">
  {% include 'header.html' %}
  <div class="container py-9 px-48">
    <h1 class="text-3xl my-6 font-black">Latest articles</h1>


    <div class="grid grid-cols-3 gap-9">
      {% for article in articles.data %}
      <div class="card bg-gray-50 rounded-lg shadow-sm pb-3">
        <div class="card-body ">
          <div>
            {% if article.background %}
            <a href="/infos/{{ article.slug }}">
              <img src="{{ article.background }}" alt="article background">
            </a>
            {% endif %}
          </div>
          <div class="flex">
            <a class="flex-1 px-3 py-1 text-sm" href="/infos/{{ article.slug }}">
              {{ article.createdAt | formatDateTimestamp  }}
            </a>
          </div>
          <h2 class="text-2xl font-bold flex">
            <a class="flex-1 px-3 py-2" href="/infos/{{ article.slug }}">
              {{ article.title }}
            </a>
          </h2>
          <div class="flex mt-3 px-3">
            {% for tag in article.tags %}
            <a class="bg-teal-700 text-xs px-3 py-1 mr-3 rounded-xl text-white" href="#">
              #{{ tag.title }}
            </a>
            {% endfor %}
          </div>
        </div>
      </div>
      {% endfor %}
    </div>

    <div class="flex justify-center  mt-6">
      {% for i in range(1, linksCount + 1) %}
      <a class="bg-purple-600 w-9 h-9 flex items-center justify-center text-white mx-1 rounded-lg" href="?page={{ i }}">
        {{ i }}
      </a>
      {% endfor %}
    </div>
  </div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Fetch one article by id or slug

Some developers like to retrieve items by id, others by slug.
You have the choice.

app.get('/articles/:slug', async (req, res) {
  const slug = req.params.slug    
  const article = await kv.articles.retrieve(slug);
  res.render('article.html', article);
})

Enter fullscreen mode Exit fullscreen mode

Then your html display data.

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script src="https://cdn.tailwindcss.com"></script>
        <style>
            article p {
                margin: 1rem 0;
            }
        </style>
    </head>
    <body class="bg-gray-200">
        {% include 'header.html' %}
        <div class="container mx-auto py-9 px-72">
            <article class="card bg-gray-50 rounded-lg shadow-sm pb-3">
                <div class="card-body px-8 py-3">
                    <div>
                        {{ article.data.createdAt | formatDateTimestamp  }}
                    </div>

                    <h1 class="text-3xl my-6 font-black">{{ article.data.title }}</h1>

                    <div>
                        <img src="{{ article.data.background }}" alt="">
                    </div>

                    <div>
                        {% for item in article.data.content %}
                            {{ item | safe }}
                        {% endfor %}
                    </div>
                </div>
            </article>
        </div>
    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Fetch tags

Same way.

app.get('/tags', async ( req, res ) => {
  const tags = kv.tags.list();
  res.render('tags.html', tags);
})
Enter fullscreen mode Exit fullscreen mode

This is the content of all tags in this blog:

{
  "data": [
    {
      "id": "89292a57-6937-4f72-9518-0070f7af9df1",
      "title": "nft",
      "slug": "nft"
    },
    {
      "id": "f72e61ac-bcb5-45ba-a191-9536ae19ea04",
      "title": "defi",
      "slug": "defi"
    }
  ],
  "meta": {
    "url": "http://keyvox.dev/api/tags"
  }
}
Enter fullscreen mode Exit fullscreen mode

Fetch all articles by tag

app.get('/tags/id_or_slug', async (req, res) => {
    const articlesByTag = await kv.articles.retrieve(req.params.id_or_slug)
    res.render('tag.html', articlesByTags)

})
Enter fullscreen mode Exit fullscreen mode

You have your blog embeded in your website very easily.

Image description

See the full example on GitHub

Top comments (0)