Introducing Hashnode GraphQL API - Public Beta

At Hashnode, we do our best to roll out the most requested features as fast and as often as possible. We have been discussing the idea of APIs for quite some time now, but unfortunately, we couldn't make significant progress in this area.

In 2019, one of our goals was to ship Hashnode APIs so that our users can build apps based on it. Today, I am happy to announce that we are launching the public beta of Hashnode GraphQL APIs. ๐ŸŽ‰๐ŸŒŸ๐ŸŽŠ

Please note that this is a pretty minimal release. It has a lot of queries and a couple of mutations. We'd appreciate it if you would send us some early feedback so we can incrementally update the APIs in accordance with your comments in the coming days.

Get Started

To get started, go to api.hashnode.com, where you'll see the GraphQL playground. You can view the documentation and schema from the two aptly named buttons on your right. You can read more about the available queries, mutations, outputs, inputs, etc from there. We are working on improving the documentation and building a website which will be available with the 1.0 release.

api.hashnode.com.png

Authentication

Authentication is based on personal access tokens. You can create/revoke them from Hashnode settings. Treat them as private keys to your Hashnode account. Always keep them confidential and safe.

Queries/Mutations which require authentication expect an Authorization header with personal access token as its value.

Making Requests

Playground

  • Fetching Hashnode's global stories feed

Query:

{
  storiesFeed(type: GLOBAL){
    title
  }
}

If you need more properties of post object, you can specify them along with title. For example, if you need title and cuid of the fetched posts, your query should look something like this:

{
  storiesFeed(type: GLOBAL){
    title
    cuid
  }
}

  • Getting your personalized feed

Before making the query, make sure you have the personal access token in Authorization header.

Query:

{
  storiesFeed(type: FOR_ME){
    title
  }
}

Header:

{
  "Authorization": "<your token here>"
}

The auth header can be added in the "HTTP Headers" section at the bottom of the playground.


  • Getting details of a post

To get the details of a post, you can make the following query:

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

The result will look something like this:

  • Getting the comments of a particular post

Query:

{
    post(cuid: "cjzid61ek002b9ys19laotbwm"){
    responses{
      reactions{
        reaction{
          image
          name
        }
        count
      }
    }
  }
}

  • Creating a new story

Mutation:

mutation {
  createStory(
    input: {
      title: "The hashnode GraphQL API is here",
      contentMarkdown: "<h1> Ahoy </h1>"
      tags: [
        {
          _id: "56744721958ef13879b94c7e",
          name: "General Programming",
          slug: "programming"
        }
      ]
    }
  ) {
    message
    post{
      title
    }
  }
}

Header:

{
  "Authorization": "<your token here>"
}

Curl

Since GraphQL requests can be made over HTTP, you can use curl to start testing the API from the command line. You can also use any HTTP library you prefer in your programming language of choice

  • Fetching Hashnode's global stories feed

Request:

curl -H "Content-Type: application/json" -X POST https://api.hashnode.com --data '{"query": "{ storiesFeed(type: FEATURED) { title }}" }'

Response:

{"data":{"storiesFeed":[{"title":"Design Patterns - Template Method"},{"title":"Getting started with Hugo and deploying to Netlify."},{"title":"Git first time setup"},{"title":"Thermal a free, open-source, cross-platform Git GUI application"},{"title":"JS Strings - Properties and Methods"},{"title":"Step 2: Single-node Docker Swarm and Smalltalk"},{"title":"Node.js Experience"},{"title":"Jasmine Testing Tutorial"},{"title":"How I attempted Image Classification in the browser using ml5.js and React"},{"title":"Demeter's Law: Don't talk to strangers!"},{"title":"Pro tip - two minute read"},{"title":"Unix, BSD, Minix, Linux - What, Who and When"},{"title":"Challenge Accepted: Build TensorFlow C Binding for Raspberry Pi in 2019"},{"title":"What's wrong with Promise.allSettled() and Promise.any()โ“"},{"title":"Dockerless, Part 1: Which tools to replace Docker with and why"},{"title":"Getting started with Docker and Smalltalk!"},{"title":"React Visualization Libraries in 2019"},{"title":"Build a chatbot in 20 minutes using Flutter and Dialogflow"},{"title":"Dialogs and Alerts on Android using Anko and Kotlin"},{"title":"What getting back on Facebook taught me"},{"title":"Why we split the management of Admin Users and End Users"},{"title":"Solution for high CPU usage with Webpack/Laravel Mix"},{"title":"This project gave me an A++ in college ๐Ÿ’ฏ๐ŸŽ“ & this is prolly my last post ๐Ÿ˜ญ"},{"title":"Design Patterns - Strategy Pattern in JavaScript"},{"title":"A Ghost Demo: How to Go Headless with Ghost CMS [Tutorial]"},{"title":"Intro to Stackbit: Build a Custom JAMstack Site in Minutes"},{"title":"Use PostgreSql with Heroku CLI in Alpine container"},{"title":"CSS selectors and it's Specificity(Priority to override other)"},{"title":"Of Pushback tractors (Bit#2)"},{"title":"Build a school timetable with python"}]}}
  • Creating a new Post

Request:

curl -H "Authorization: <your token here>" -H "Content-Type: application/json" -X POST https://api.hashnode.com  --data '@query.json'
$ cat query.json
{
    "query": "mutation createStory($input: CreateStoryInput!){ createStory(input: $input){ title } }",
    "variables": {
        "input": {
            "title": "What are the e2e testing libraries you use ?",
            "contentMarkdown": "I was wondering what e2e testing libaries do you use",
            "tags": [
                {
                    "_id": "56744723958ef13879b9549b",
                    "slug": "testing",
                    "name": "Testing"
                }
            ],
            "coverImage": "https://cdn.hashnode.com/res/hashnode/image-dev/upload/v1562665620141/tc-h-erqF.jpeg",
        }
    }
}

Response:

{"data":{"createStory":{"title":"What are the e2e testing libraries you use ?"}}}

Javascript

  • Fetching Hashnode's global stories feed

Code:

const fetch = require('node-fetch')

fetch('https://api.hashnode.com', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'Authorization': "<your token here>"},
    body: JSON.stringify({
        query: 'query { storiesFeed(type: GLOBAL){ title } }'
    }),
})
    .then(res => res.json())
    .then(res => console.log(JSON.stringify(res)))

Result:

{"data":{"storiesFeed":[{"title":"Design Patterns - Template Method"},{"title":"Getting started with Hugo and deploying to Netlify."},{"title":"Git first time setup"},{"title":"Thermal a free, open-source, cross-platform Git GUI application"},{"title":"JS Strings - Properties and Methods"},{"title":"Step 2: Single-node Docker Swarm and Smalltalk"},{"title":"Node.js Experience"},{"title":"Jasmine Testing Tutorial"},{"title":"How I attempted Image Classification in the browser using ml5.js and React"},{"title":"Demeter's Law: Don't talk to strangers!"},{"title":"Pro tip - two minute read"},{"title":"Unix, BSD, Minix, Linux - What, Who and When"},{"title":"Challenge Accepted: Build TensorFlow C Binding for Raspberry Pi in 2019"},{"title":"What's wrong with Promise.allSettled() and Promise.any()โ“"},{"title":"Dockerless, Part 1: Which tools to replace Docker with and why"},{"title":"Getting started with Docker and Smalltalk!"},{"title":"React Visualization Libraries in 2019"},{"title":"Build a chatbot in 20 minutes using Flutter and Dialogflow"},{"title":"Dialogs and Alerts on Android using Anko and Kotlin"},{"title":"What getting back on Facebook taught me"},{"title":"Why we split the management of Admin Users and End Users"},{"title":"Solution for high CPU usage with Webpack/Laravel Mix"},{"title":"This project gave me an A++ in college ๐Ÿ’ฏ๐ŸŽ“ & this is prolly my last post ๐Ÿ˜ญ"},{"title":"Design Patterns - Strategy Pattern in JavaScript"},{"title":"A Ghost Demo: How to Go Headless with Ghost CMS [Tutorial]"},{"title":"Intro to Stackbit: Build a Custom JAMstack Site in Minutes"},{"title":"Use PostgreSql with Heroku CLI in Alpine container"},{"title":"CSS selectors and it's Specificity(Priority to override other)"},{"title":"Of Pushback tractors (Bit#2)"},{"title":"Build a school timetable with python"}]}}
  • Creating a post

Code:

const fetch = require('node-fetch')

fetch('https://api.hashnode.com', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'Authorization': "<your token here>" },
  body: JSON.stringify({
    "query": "mutation createStory($input: CreateStoryInput!){ createStory(input: $input){ title } }",
    "variables": {
      "input": {
        "title": "What are the e2e testing libraries you use ?",
        "contentMarkdown": "I was wondering what e2e testing libaries do you use",
        "tags": [
          {
            "_id": "56744723958ef13879b9549b",
            "slug": "testing",
            "name": "Testing"
          }
        ],
        "coverImage": "https://cdn.hashnode.com/res/hashnode/image-dev/upload/v1562665620141/tc-h-erqF.jpeg",
      }
    }
  }),
})
  .then(res => res.json())
  .then(res => console.log(JSON.stringify(res)))

Result:

{"data":{"createPost":{"title":"What are the e2e testing libraries you use ?"}}}

Client Libraries

Client libraries will provide you with the fastest and most comprehensive way to access the API and can assist in handling auth, formatting your requests and your responses. Learn more about Apollo Client here.


These are just a few examples, feel free to explore the API further. We are very excited to see what you folks are going to build. In case you are looking for some ideas, here are a few off the top of my head:

  • A Discord/Slack bot that fetches the top Hashnode stories and posts them periodically
  • The best of Hashnode in a different UI -- e.g. A Hackernews style website that showcases top, featured and recent stories from Hashnode.
  • Posting to Hashnode from the comfort of your terminal. This one is for terminal lovers. If you are writing quick tips or a short article and don't want to go to Hashnode to write them, you can always post them by using our API.

We are just getting started. So, feel free to share any bugs, feedback or your cool ideas in our Discord server. We look forward to keeping up with your requests and releasing more features in the coming days!


Update: The following are the features/functionalities we are working on for 1.0, we are targetting last week of August to put things together and cut a release.

Post

  • Create post
  • Update post
  • Delete post
  • Get post(s)
  • React to post

Response

  • Create response
  • Update response
  • Delete response
  • Get response(s)
  • React to response

Reply

  • Create reply
  • Update reply
  • Delete reply
  • Get reply/replies
  • React to reply

Nodes

  • Get Node(s)
  • Follow a Node
  • Top / Recent posts

User

  • List users
  • Get details of a user
  • Get followers of a user
  • Follow a user
  • Update user profile
  • Get stories by a user

Devblog

  • Get posts from a blog

Update

Comments (27)

Add a comment
Fahmi Akbar Wildana's photo

Congrats ๐ŸŽ‰

Aravind's photo

Software Engineer At Hashnode

Thanks Fahmi Akbar Wildana, let us know your feedback.

Mohd Shad Mirza's photo

Awesome

Marco Alka's photo

Very nice! I love it! Quick questions:

  • How will you do API versioning?
  • Will you provide official libraries for selected languages (TS, Java, Go, Python, Rust,...)? Will there be a partner-program for maintainers of (unofficial) libs?
  • What is the rough scope for the 1.0 release? What about user management, messaging, notifications,... ?
  • Will DevBlog and future endeavors also be included in the API?
Show all replies
Marco Alka's photo

Software Engineer & Mentor

Aravind

Thank you for answering all of my questions and being so open about the whole process!

In the long term, we see the API to provide the same functionalities as the web app.

That sounds awesome. Hashnode as an API ๐Ÿ˜‚ I love this idea! It certainly allows you to make radical front-end changes easily, and the community can hook into everything going on, ideally providing new opportunities and possibilities. A living platform.

Siddharth Vishvanath (Sid)'s photo

Awesome ๐Ÿ‘

Ashwin Shenoy's photo

Great job on the new API ! Can you please point me towards the API docs ? I can't seem to find it in this post. Thanks

Aravind's photo

Software Engineer At Hashnode

Hey Ashwin Shenoy, proper docs will be released along with the stable version. Can you checkout the playground and the accompanying docs in the meantime?