Skip to main content

Command Palette

Search for a command to run...

How I Queried Hashnode's GraphQL API to display my hashnode blog posts on my Nuxt Website

Published
6 min read
How I Queried Hashnode's GraphQL API to display my hashnode blog posts on my Nuxt Website
I

Software Engineer from Lagos, Nigeria

Hi there dev,

I am Idris (if you don't already know), I recently started building my portfolio website at idrislawal.com with Nuxt JS and realized I needed to have my blog posts from hashnode also on my website, so I thought to myself, how do I make this happen? I contacted Bolaji Ayodeji to enquire about hashnode's API and he directed me to api.hashnode.com which is a graphQL playground to tryout hashnode's APIs and see the expected responses, it also contains the necessary documentation of all the APIs. Screenshots below.

hasnode playground-1.png The red arrow on the right shows the documentation panel and on the left is a sample query.

The focus in this article will be how I queried the API to get what I needed. So what did i need? I needed to get details of all my blog posts listed out. Then, I needed to be able to query each post's content. Basically Two Queries.

Here is the query I used to get all my blog posts listed

{ user(username: "titanium"){publication{posts {title,cuid,coverImage,brief}}}

If you are a bit familiar with graph QL, you might be expecting the query to look more like this

{ user(username: "titanium")
         {publication
               {posts 
                     {title
                      cuid
                      coverImage
                      brief
                      }
                 }
           }
}

Explanation on why it isn't in this format later. Note: The query above requires an "Authorization" header. We will see how this is done later.

Now, for the second query, I needed to also query contents of each post. So here is the (sample) query for that.

{post(cuid: "cjyc4klzr0031wds1yp4b2xn0") {title,content}}

Next, I needed a way to call the API from my website. There are a couple of options to do this, I opted to use the Apollo-fetch library provided by the Apollo GraphQL team. I use yarn, so,

NEW EDIT (Sept 2020): The apollo-fetch library has been archived on Github and is now Deprecated

yarn add apollo-fetch

Next, in my Nuxt website, I needed to provision a store module to get the data. In the store folder, I created a getPosts.js file which will contain my API calls. Below is what it looks like,

NEW EDIT (Sept 2020): You do not need a valid authorization token to do this

const { createApolloFetch } = require("apollo-fetch");

const fetch = createApolloFetch({
  uri: "https://api.hashnode.com"
});

fetch.use(({ request, options }, next) => {
  options.headers = {
    Authorization: "jjjsu3hj1111111199999jj"
  };
  next();
});

const state = () => ({
  posts: [],
  singlePost: {}
});

const getters = {
  getPosts(state) {
    return state.posts;
  },
  getSinglePost(state) {
    return state.singlePost;
  }
};

const actions = {
  fetchPosts(context) {
    fetch({
      query:
        '{ user(username: "titanium"){publication{posts {title,cuid,coverImage,brief}}} }'
    }).then(res => {
      context.commit("setPosts", res.data.user.publication.posts);
    });
  },
  fetchSinglePostDetail(context, data) {
    fetch({
      query: `{post(cuid: "${data.cuid}") {title,content}}`
    }).then(res => {
      context.commit("setSinglePost", res.data.post);
    });
  }
};

const mutations = {
  setPosts(state, data) {
    state.posts = data;
  },
  setSinglePost(state, data) {
    state.singlePost = data;
  }
};

export default {
  state,
  getters,
  actions,
  mutations
};

In the actions object above, notice the query field is a string, hence the reason for compressing the query params as earlier mentioned.

Before making the query, make sure you have the personal access token in "Authorization" header. Checkout this hashnode article to learn how you can generate your personal access token.

On my blogposts page. I have PostCard.vue component which renders individual posts as cards. And a computed property called posts which gets the posts from state.

//blogposts.vue

<v-row>
        <v-col md="4" v-for="(post, index) in posts" :key="index">
          <nuxt-link :to="`/post/${post.cuid}`">
            <PostCard
              :postTitle="post.title"
              :postImage="post.coverImage ? post.coverImage : defaultImage"
              :postBrief="post.brief"
            />
          </nuxt-link>
        </v-col>
      </v-row>


<script>
import PostCard from "@/components/PostCard";

 computed: {
    posts() {
      return this.$store.state.getPosts.posts;
    }
  },
  created() {
    this.$store
      .dispatch("getPosts/fetchPosts")
      .then(() => eventBus.$emit("toggle-loader"));
  }
</script>

The Nuxt-link above passes the cuid back to the store to query the API for a single post and opens new page I have created at /post/_cuid.vue to render its contents. The underscore, tells Nuxt that the page will contain dynamic content.

See what I have so far at idrislawal.com/blogposts

How you choose to render your content is upto you!

I hope this has been insightful and educative, catch you next time, ^_^

S
spiritbro5y ago

hello do you know how to post publication story using graphql?

i have tried like this but no luck:

mutation{createPublicationStory(publicationId:"helloguys",input:{title:"trying da graphql ",contentMarkdown:"wish me ",tags:[]}){code,message,success}}
P

Interesting!

T

Hello 👋 Interesting post!

The user -> publications -> post query appears to return only 6 entries and not support pagination. Have you found an undocumented workaround or an alternative query?

I also noticed your post detail page no longer works on your Nuxt site.

I also just wanted to note a security concern you may want to address—your API key is exposed in the Authorization header. You may not be aware, but this token allows both read and write privileges. A bad actor could create posts on your blog without you knowing since your key is exposed.

From the developer dashboard:

Personal Access Token is like a private key to your Hashnode account [...] Never disclose your access tokens and always keep them private.

If you use Nuxt as a static site generator, you can work around this by implementing asyncData() with a process.server check so that you only make the request when you're generating your website server-side, that way your token is not exposed:

export default Vue.extend({
  components: {
    // ...
  },

  asyncData () {
    if (process.server) {
      return getPosts()
        .then((data) => {
          return { 
            posts: data.posts 
          }
        })
    }

    return { 
      posts: [] 
    };
  },

  data() {
    return {
      posts: []
    };
  },

})
I

Wow, how did I miss this? Thanks a lot for your valuable feedback. You notes here are absolutely correct. I started making some changes to my portfolio page and broke a couple of things, but I haven't had the time to fix it up.

Thank you!

S

Nice stuff. Thanks for sharing. Do note that fetching personal blog posts of a user doesn't require an auth key. It's a public endpoint.

1
I

I actually thought, it did. Its probably best I leave the auth key though, so I wouldn't have to worry about whether the endpoint is public or private. Thank you!

S

This is amazing! Thanks Idris Lawal for sharing this. :)

1