A while ago, I migrated my site from WordPress to Gatsby, a static site generator that runs on JavaScript/React. Gatsby recommends Disqus as a possible option for comments, and I briefly migrated all my comments over to it…until I looked at my site on a browser window without adblocker installed. I could see dozens of scripts injected into the site and even worse – truly egregious BuzzFeed-esque ads embedded between all the comments. I decided it immediately had to go.
I had no comments for a bit, but I felt like I had no idea what the reception of my articles was without having any place for people to leave comments. Occasionally people will leave useful critiques or tips on tutorials that can help future visitors as well, so I wanted to try adding something very simple back in.
I looked at all the options, but I really didn't want to invest in setting up some third party code that I couldn't rely on, or something with ads. So I figured I'd set one up myself. I designed the simplest possible comment system in a day, which this blog now runs on.
Here's some pros and cons to rolling your own comment system:
Pros
- Free
- No ads
- No third party scripts injected into your site
- Complete control over functionality and design
- Can be as simple or complicated as you want
- Little to no spam because spambots aren't set up to spam your custom content
- Easy to migrate – it all exists in one Heroku + Postgres server
Cons
- More work to set up
- Less features
- Need to set up manual anti-spam measures and moderation
If you've also struggled with this and wondered if there could be an easier way, or are just intrigued to see one person's implementation, read on!
Introduction
This guide will not be a full, guided walkthrough – however, all the steps to create this are documented from start to finish in Create and Deploy a Node.js, Express, & PostgreSQL REST API to Heroku. The comments API is a Node + Express server connected to a Postgres instance hosted for free on the hobby tier of Heroku (Hopefully I don't go over the 10,000 row limit any time soon). A combination of that article and what I've documented here can get you all the way to having your own comment system.
Note: Comments overall aren't a big deal to me, so I don't care if I'm just running some little hobby API I created, or if it goes down for any reason. I think it should be pretty solid, but obviously if your needs are more professional than mine, you should go ahead and buy Disqus or something.
The comments API consists of three parts:
The frontend is written for React, but if you know how to make a form and an API call, it can be easily adjusted to whatever static system you're using.
Database
The first step assumes we'll be setting up a Postgres database called comments_api
with a comments
table.
In the comments_api
database, I created a comments
table, with ID
, name
, date
, and text
. The slug
refers to the article URL – so for https://example.com/how-to-bake-a-cake
, the slug would be how-to-bake-a-cake
. Finally, I added parent_comment_id
in case you want to have the ability to reply to comments.
You could probably get more fancy with it and add website, email, upvotes and other features, but I just wanted it to be simple. I'm not adding in any login or OAuth/user authentication either, which makes it even more simple, but comes with the drawbacks of an anonymous online system.
API
In Create and Deploy a Node.js, Express, & PostgreSQL REST API, I document how to set up an Express server and make a Postgres pool connection.
The aforementioned article goes much deeper into production level concerns of a Node.js server, such as error handling, validation, and brute force rate limiting.
In our simplified, development example setup, we'll require express
, a Node.js server, plus bodyParser
and cors
to allow our app to parse and request the data, and pg
to create a Postgres pool connection.
This article is using default values for the Postgres connection –
user
as username,password
as password, etc.
Remember that this example is simply for demonstration purposes and development.
Get all comments
First, I want a GET
query that will just return everything to Node.js, ordered by date. This is just for me to have, so I can easily review all comments.
Get comments by page slug
More importantly, I want a query that will only return the comments that match the current page's slug. This is the query I'll use for each article.
Create a comment
Add the ability to POST
a new comment, which people will be able to do through the HTML form.
Update an existing comment
As moderator, I want the ability to update an existing comment. Commentors won't be able to edit their comments, because they're all anonymous. This will be a protected endpoint.
Delete a comment
Another protected endpoint, only I will have the ability to delete a comment.
Putting it together
We have our two GET
s, a POST
, PUT
, and DELETE
.
Front End
Again, for the frontend I'm using React as an example, but the concept is the same for any template system. In whatever your post template file is, use JavaScript to make a fetch
or axios
call to your comment API, and save the data in state somewhere. Once I retrieve the JSON response from the API server, which will be an array of comment objects, I can pass it to wherever I'm displaying the comments.
Sorry, I'm not using hooks yet. It's okay, deep breath. We'll get through this.
In this case, that will be a Comments
component.
The Comments
component will contain both the form to submit a comment, and the list of existing comments if there are any. So in state, I'll save the comments list, and an object to store new comment state for the form.
I'll admit this code is not the most pristine I've ever seen, but as I mentioned, I wrote the thing in a day, so feel free to refactor and write however you want.
When a comment is submitted, I'll use fetch
once again, this time with the post
method. If everything went through correctly, append the new comment to the comments array, and reset the new comment.
I'll also have an onChange
handler for the form.
We can start the render lifecycle now.
I made some simple error or success messages to show after submitting the form.
The comment form only consists of name and comment in my case, as I decided to go the Sivers route and only allow comment replies by yours truly on the site.
Finally, we'll display the form and the comments. I decided to either display the form or a success/error message. A visitor won't be able to leave two comments in a row without reloading the page.
After that, it's just a matter of looping through the comments and displaying them. I've made comment replies incredibly simple – only one reply allowed per post, and no nesting.
Conclusion
You'll probably also want to add in some anti-spam moderation system, like adding a moderated
column to the comments, setting it to false
by default, and manually setting it to true
if you approve the comment.
I hope this helps out someone who wants a simple, free system for their own personal site. I like reinventing the wheel and making things from scratch. It's fun, and I learn a lot.
For more information on building contact forms with Gatsby, check out the docs reference guides.