Create a NuxtJS blog with a free BlogHunch account

Create a NuxtJS blog with a free BlogHunch account

BlogHunch is a next-generation blogging platform that lets you get started with your publication in 60 seconds. It has a full-featured API that lets you connect your NuxtJS application to fetch data. In this tutorial, we will use the BlogHunch API to build a NuxtJS blog in 5 minutes or less.

NuxtJS is one of the most popular frameworks out there that helps to create SSR, SSG, and SPA applications easily with VueJS. In this tutorial, we will learn how to build a NuxtJS blog with BlogHunch.

Setting up BlogHunch

Let’s start setting up our NuxtJS blog with BlogHunch.

Here is a smart video to save your time and help you get started with your first BlogHunch blog.

Once your BlogHunch blog is ready, it’s time to create the API key to connect to your NuxtJS application.

Setting up NuxtJS blog

Now we have our API key ready along with our blog. It’s time to set up the NuxtJS application and pull some data.

Create a new Nuxt application with the following command. I am choosing Tailwind for the UI.

npm init nuxt-app <project-name>

Once it’s done, we will need to install the additional packages we need. The first one is the official Node API and the second one is ExpressJS.

npm install express --save
npm install bh-node-api

We can call the API from the front end as well but it’s not a good idea to expose the API key to the public.

Now you have a question why ExpressJS when we can do an SSR with NuxtJS and call the API within asyncData or fetch. The answer is yes we can put the API key in privateRuntimeConfig and do the same thing.

However, we will be using server-middleware with Express for this tutorial.

Server Middleware Setup

Create a folder called server-middlware at the root of your NuxtJS project. Let’s add a file called app.js within it.

We will simply create an Express server with 2 different routes, one to fetch all posts and the other one to fetch a single post. Let’s start by setting up Express and Bloghunch API.

import express from 'express';
import { getAllPosts, getPost } from 'bh-node-api';

const app = express();
app.use(express.json());

// apiKey must be generated from BlogHunch application
const apiKey = '';
// Your BlogHunch blog domain or subdomain
const domain = 'testblog.mybloghunch.com';

Now we have everything ready to set up our routes and start fetching data.

// Fetch all posts
app.get('/posts', async (req, res) => {
  try {
    const posts = await getAllPosts(apiKey, domain);
    res.json(posts);
  } catch (e) {
    console.log(e);
  }
});

// Fetch single post
app.get('/posts/:slug', async (req, res) => {
  try {
    const post = await getPost(apiKey, domain, req.params.slug);
    res.json(post);
  } catch (e) {
    console.log(e);
  }
});

In the above code we are using the two different methods (getAllPosts, getPost) provided by the BlogHunch Node API to fetch the data easily.

Display the data

Now it’s time to display the data. We will need 2 pages – One for displaying all the posts and the other one for displaying a single post.

Let’s start with the first page – index.vue.

<template>
  <div>
    <h1 class="text-xl md:text-4xl pb-6 font-bold">
      NuxtJS blog powered by BlogHunch
    </h1>

    <div class="grid grid-cols-12 gap-6">
      <div
        class="col-span-12 md:col-span-4"
        v-for="post in posts"
        :key="post.id"
      >
        <nuxt-link :to="`/${post.slug}`">
          <div class="flex flex-col rounded-lg shadow-lg overflow-hidden">
            <div class="flex-shrink-0">
              <img
                class="h-48 w-full object-cover"
                :src="post.featured_image"
                :alt="post.title"
              />
            </div>
            <div class="flex-1 bg-white p-6 flex flex-col justify-between">
              <div class="flex-1">
                <a href="#" class="block mt-2">
                  <p class="text-xl font-semibold text-gray-900">
                    {{ post.title }}
                  </p>
                  <p class="mt-3 text-base text-gray-500">
                    {{ post.content_text.substr(0, 150) }}
                  </p>
                </a>
              </div>
              <div class="mt-6 flex items-center">
                <div
                  class="flex-shrink-0"
                  v-if="post.author && post.author.avatar"
                >
                  <a href="#">
                    <span class="sr-only">Daniela Metz</span>
                    <img
                      class="h-10 w-10 rounded-full"
                      :src="post.author.avatar"
                      :alt="post.author.name"
                    />
                  </a>
                </div>
                <div class="ml-3">
                  <p class="text-sm font-medium text-gray-900">
                    <a href="#" class="hover:underline">
                      {{ post.author.name }}
                    </a>
                  </p>
                  <div class="flex space-x-1 text-sm text-gray-500">
                    <time
                      :datetime="$dayjs(post.created_at).format('YYYYY-MM-DD')"
                    >
                      {{ $dayjs(post.created_at).format('MMM DD, YYYY') }}
                    </time>
                    <span aria-hidden="true"> &middot; </span>
                    <span> {{ post.reading_time }} min read </span>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </nuxt-link>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  async asyncData() {
    const res = await fetch('http://localhost:3000/api/posts');
    const data = await res.json();

    return {
      posts: data,
    };
  },
};
</script>

On this page, we have an asyncData method that fetch the data from our server-middleware. Once we have the data fetched we are loop through it in the template.

Now, let’s move to the other page. We can name it slug.vue or we can create a folder called slug and then index.vue inside it.

<template>
  <div>
    <div v-if="post" class="max-w-3xl mx-auto">
      <h1 class="text-xl md:text-4xl pb-6 font-bold">{{ post.title }}</h1>

      <img :src="post.featured_image" :alt="post.title" class="block w-full" />

      <div class="p-4">
        <article
          class="prose lg:prose-md max-w-none"
          v-html="post.content"
        ></article>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  async asyncData({ params }) {
    try {
      const res = await fetch(`http://localhost:3000/api/posts/${params.slug}`);
      const data = await res.json();

      return {
        post: data,
      };
    } catch (e) {
      console.log(e);
    }
  },
};
</script>

Here also we are using the asyncData to fetch the post details.

Deploy

Finally, our NuxtJS blog is ready to be deployed. You can follow the official deployment docs of NuxtJS.