Will Murphy's personal home page

Adding Comment Capability

Hugo doesn’t provide comments out of the box. Wordpress did, but you had to make an account, which not everyone wanted to do. I could pay for a service that adds comments to my blog but the whole point of this blog is to get better at using AWS, so I’m going to roll my own comment engine. It seems like Hugo natively supports Disqus and can be configured to work with some alternatives to it, so to be clear, this is a learning project, not a recommendation for how to proceed. If you have a goal to get comments on your blog quickly, use one of the pre-built approaches. Since my goal is learning, not quickly achieving the comment feature, I’m going to proceed with building my own.

I have a few requirements:

  1. No login - you should be able to post a comment without proving who you are
  2. No spam - random folks and bots from the internet should not be able to post ads or whatever as comments

In order to achieve both of these, there has to be a review, so this post is about my early design for the comment posting and review system.

Let’s try to get more specific about the requirements of the system:

  1. It has to be able to list the comments that go on a particular post
  2. It has to accept comments on a post
  3. It has to let the blog author approve comments before they end up in list 1

My first thought is to use DynamoDB to store the list of comments. DynamoDB is optimized for reads and writes when you know the primary key, so I can just use an identifier for the post as my primary key in DynamoDB, and keep a JSON document of comments in there. Then, for reading the comments, I can put javascript in the footer of each post calls Lambda through API Gateway and gets back the list of comment IDs. One limitation of DynamoDB is the 400 KB item sites, but 400,000 ASCII characters seems like a lot for comments on a single blog post, so I think that’s a reasonable place to start.

I think to accept comments, I’ll render a form at the bottom of pages that posts back to the API Gateway and Lambda solution, and have the lambda trigger a state machine. One of the main use cases for state machine is human-in-the-loop approval systems, which is exactly what we’re building. The setup will look like this:

  1. User clicks “post comment”
  2. Javascript running on the post sends the comment body to a Lambda through API Gateway
  3. The Lambda starts a state machine
  4. The state machine emails me an email with an approve link, a deny link, and the text of the comment
  5. If I click the deny link, the step function just ends, and the comment never sees the light of day
  6. If I click the approve link, the step function sends the comment to a lambda.
  7. The lambda fetches all the comments for that post from DynamoDB, adds the new one, and writes it back.

One caveat to this system is that it assumes that a given post has a stable ID that persists forever. I could use the post’s slug or title, but then if those ever changed, all the comments would be erased. A better solution would be to give each post a UUID that can never change, and make it available to client side javascript. Probably the mechanism for persisting that UUID would be Hugo’s user-defined front-matter feature, but generating it might require some customization. I’d prefer being able to teach hugo new to generate a new UUID and put it in the front matter when I run a post, but that may not be possible. If it’s not, I’ll probably write a short script that invokes hugo new and then edits the resulting file to add the UUID. That would feel kind of hacky, but it would also work fine and be easy.

Now we have a list of code changes that we can get to work on:

  1. Add custom front-matter to all new posts, giving a UUID to each post
  2. Write a once-off script to add UUIDs to my existing posts
  3. Update my html templates so that this UUID gets render client side
  4. Set up an API Gateway endpoint for the blog
  5. Write a “getComments” lambda that takes a post UUID, queries DynamoDB for the record with that ID, and formats the result
  6. Update my html templates so that my posts include javascript that will call “getComments” on page load, and maybe on a cron (in case someone comments on the post while someone has the page open).
  7. Write a “submitComment” lambda that takes a post UUID and JSON document representing a comment, and starts a state machine
  8. Write a “persistComment” lambda that takes a post UUID and JSON document representing a comment, and appends it to the list of comments about that post in DynamoDB
  9. Write a state machine that follows the flow described above.
  10. Update my html templates so that my posts include javascript that can post to the “submitComment” lambda.

Each of these changes could have its own blog post, so it looks like I have just accidentally planned a series of blog posts on enabling comments on blog posts. Hopefully by the end of it, you’ll be able to let me know what you think!

Till next time, happy learning!
– Will


Note: recently submitted comments may not be visible yet; the approval process is manual. Please be patient, and check back soon!

Join the conversation!