Most of the features I keep trying to add to my blog are due to the inspiration I get from other people's work. I came across this one for the very first time on Lee Robinson's blog, and I've always wanted something like that.
I read through his approach and found out that he resorted to using firebase to update the views of each article on his blog through Next.js' API routes. I went on to try it, and I've got to say, I don't know why a particular thing that worked for Developer A never works for me. The same thing happened when I was trying to build this blog.
Although there were other alternatives I discovered from some articles on DEV, that required the use of Supabase to store the views, I wasn't comfortable with the tool, probably because I was a bit skeptical because it isn't something I'm familiar with, compared to its other counterparts like MongoDB and Firebase.
Okay, I don't think there is a concrete reason why I chose Mongo. But, it is somewhat tied to the research I made on how I'd be able to implement this feature after taking a look at the approach that other people used, and because it is a popular database used by many backend developers who use Node.js. Luckily, MongoDB provides a Node.js driver that I can use to interface with its APIs.
There aren't so many resources around integrating a static site like mine with this tool. I had no idea about what I was doing. All I had at the back of my mind was that I want to increment the views of an article when its route is visited by anyone.
And that was the bane of my research. I remember asking a question on stackoverflow on how I'd be able to accomplish this. I think the question has been deleted or made hidden, because it is "opinion-based", and is currently not accepting answers. But, give it a look, nonetheless.
Setting up the cluster that would house my database, and the collection(s) that will be there in the future, was a bit stressful. But, I stumbled upon this guide that walked me through the process.
Since I'd be needing a medium of accessing the database, and the collections in my cluster, I'll be needing the Next.js API route, to serve as an endpoint that I'll consume via a
POST request which updates the views whenever it is visited.
You know how we have dynamic routes in Next.js right? The same thing applies to API routes, since this feature I want to implement depends on the change of the slug that is appended aft the blog's URL. In the pages folder.
Below, you'll find the code snippet of the API endpoint, you'll notice how I'm using the square brackets
 naming convention. This is just to inform Next.js that the data from this endpoint is a dynamic one.
Okay, the snippet above is a bit long, But, in summary, this is what is happening there: First, I'm importing the mongoose model that I created beforehand. This is to ensure that the document in the collection has the appropriate schema and data types. In the next lines, I'm destructuring the
slug parameter from the
req — request object, since the slug is what I'll be sending via the POST request to the database.
From line 5 downwards, I'm using the
findOneAndUpdate method of the mongoose model to increment the views of an article when its slug is found in the collection with the
$inc method. The
upsert property made it possible for me to save the updated article schema into the collection by using the
.save() method on the mongoose model.
In between the lines, you'll notice a little error-handling process with a reusable function I declared, far down.
Take a look at what the schema looks like, below. You'll also notice that I destructured the
NEXT_PUBLIC_MONGO_URI from the
process Node object. Instead of doing something like:
If you're wondering how I got the environment variable I'm using, Kindly consult this MongoDB Atlas + Next.js guide I shared previously. When you've obtained your environment variable, you can come back here and use my approach of connecting to the database like so:
Using the API wasn't an issue so long as I connected to my cluster and got the API route working correctly, all I needed was to create a reusable component that returns the number of views an article gets. The snippet below shows a representation of the component.
At first, I tried using SWR to render the number of views, but it was flawed, for my use-case at least, because anytime I hit the
views endpoint I kept on getting more than one response, making every visit to a unique slug to be incremented unnecessarily.
Other than that, my component looked a little bit similar to what you're seeing below.
Not only was this approach taking up so much space, but it also wasn't even yielding the correct result. I even went on to add the
revalidate key, in hopes that it would fix the multiple responses issue. But, it didn't, maybe I was missing something though.
When it was time for me to deploy the feature and see it live, nothing worked as I expected it to. I kept on getting this very annoying error — "Bad error, missing form" — whenever I check my networks tab in dev tools. I also noticed that the status code of my requests was 400. I was soo pissed, to the extent that I just abandoned figuring out a way to fix it for almost a week or so.
But, when I found a fix for it, I wrote about it here, kindly read it.