Tips / Tops #
So, yesterday i gave a few family memebers a link to this new fresh blog. They found it amazing and very cool, but they did have some suggestions on adding a Likes system, so people can like my posts. Another suggestion was on making the comment system more open to users without Github. This is also a very good suggestion as there might be a better comments system thats also opensource/less dependent on bigtech like Microsoft or Google or whatever and makes it so outside people without a github account can also leave a comment on my posts. Other than that they liked the blog very much and even though they are not that tech savvy, they like reading how and what i write nonetheless. I will tackle the commenting system later.
Solution #
So i started looking into a Likes system for the blog. I know Hugo and blowfish have a Like system embedded, but that makes use off google’s firebase API and i want to avoid bigtech where it’s possible. Then i had an idea. What if i make a more DIY solution? So i started looking into that.
Software/frameworks #
I already knew python had a module called FastAPI, which allows building good API’s for web frameworks.I am also a bit more familiar and comfortable with python, as its the language i began coding in when i was a beginner and ocasionally i still code in this language. It also is the language I wrote my python project, my DVD-Logo screensaver in. For the database, i will use SQLite a very popular database solution. This database will store the amount of likes.
Backend #
So for the backend, i will spin up a fresh LXC in proxmox, which will run the python FastAPI and SQLite stack. The container does not need to be powerfull and I decided on 4gb storage and 512-Megabytes of ram and 1 core. It will simply run the Application stack and that be it. I made a SystemD service that auto starts the stack at bootup, so it can be a set and forget solution.
How it will work #
So We have the software stack, backend and frontend. The python fastAPI software stack will run on the backend, the LXC container and then the frontend (my blog) will use some Javascript to talk to and receive data from this backend. I will make an additional [api.309electronics.net] entry in caddy and in porkbun so the website can talk to it. When you like a post, it will make an API call to the API that goes like this: “Okay API, increment the likes on post X” and that will increment the count in the database. Then when the website wants to request how many likes a post has, it makes an API call and goes like “Okay API, give me the value off how many likes” and it will update the count on the website.
For anyone curious, here is the code i wrote. #
I wrote it mostly myself, but used claude Ai to optimise it and also to plan out this stuff. I am normally not a fan off AI but litteraly everyone uses AI these days so i’ll use it too. And while many people use Ai to vibecode whole apps or programs for them while they sit back in their lazy chair or go to sleep, I use it as a tool and I dont let it replace me, cause i do coding with passion and skills and try not to be lazy.
Below is the code i came up with for the frontend (likes.html): #
<script>
const API = "https://api.309electronics.net";
const POST = window.location.pathname;
const STORAGE_KEY = "liked:" + POST;
async function fetchLikes() {
try {
const res = await fetch(`${API}/likes?post=${encodeURIComponent(POST)}`);
const data = await res.json();
document.getElementById("likes-count").textContent = data.likes;
} catch {
document.getElementById("likes-count").textContent = "n/a";
}
}
async function addLike() {
if (localStorage.getItem(STORAGE_KEY)) {
document.getElementById("likes-msg").textContent = "You already liked this post.";
return;
}
try {
const res = await fetch(`${API}/likes?post=${encodeURIComponent(POST)}`, {
method: "POST"
});
const data = await res.json();
document.getElementById("likes-count").textContent = data.likes;
localStorage.setItem(STORAGE_KEY, "1");
document.getElementById("likes-btn").style.opacity = "0.5";
document.getElementById("likes-msg").textContent = "Thank you :) !";
} catch {
document.getElementById("likes-msg").textContent = "ERROR: Cant connect to the Likes-API. Please try again later.";
}
}
if (localStorage.getItem(STORAGE_KEY)) {
document.addEventListener("DOMContentLoaded", () => {
document.getElementById("likes-btn").style.opacity = "0.5";
document.getElementById("likes-msg").textContent = "You already liked this post.";
});
}
fetchLikes();
</script>As you can see, its not really difficult to implement (Okay, maybe for me).
Some off the Backend code (main.py): #
from fastapi import FastAPI, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
import sqlite3
import os
app = FastAPI()
# CORS so your blog frontend can talk to the API
app.add_middleware(
CORSMiddleware,
allow_origins=["https://blog.309electronics.net"],
allow_methods=["GET", "POST"],
allow_headers=["*"],
)
DB_PATH = "likes.db"
def get_db():
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
return conn
def init_db():
conn = get_db()
conn.execute("""
CREATE TABLE IF NOT EXISTS likes (
post_path TEXT PRIMARY KEY,
count INTEGER DEFAULT 0
)
""")
conn.commit()
conn.close()
init_db()
@app.get("/likes")
def get_likes(post: str):
conn = get_db()
row = conn.execute(
"SELECT count FROM likes WHERE post_path = ?", (post,)
).fetchone()
conn.close()
return {"post": post, "likes": row["count"] if row else 0}
@app.post("/likes")
def add_like(post: str, request: Request):
conn = get_db()
conn.execute("""
INSERT INTO likes (post_path, count) VALUES (?, 1)
ON CONFLICT(post_path) DO UPDATE SET count = count + 1
""", (post,))
conn.commit()
row = conn.execute(
"SELECT count FROM likes WHERE post_path = ?", (post,)
).fetchone()
conn.close()
return {"post": post, "likes": row["count"]}And then i only had to add a partial to layouts/partials/comments.html and thats it.
{{ partial "likes.html" . }}I will probably refine the solution and maybe modify/add some things to make it work better and more neater. Claude AI really did provide some good help and it really feels like Lcaude is my consultant or employee i can talk to and plan and improve with. He is less off a peoples-pleaser than ChatGPT and actually researches facts and thinks a bit before just mindlessly nodding ‘yes’. He will really think like an engineer/software developer does. “Wait is that possible?” instead of with ChatGPT: “Thats definitely possible” and leading users into an endless rabbit hole off breaking stuff and breaking them even more. ChatGPT used to be good but Claude and Gemini have beaten it in my honest opinion. And i believe i heard that ChatGPT was used in the American Military (but i am not 100% sure). So while i am not a huge AI fan and still honestly want this AI bubble to pop already, Claude has kind of redeemed my looks on AI and there are definitely upsides to AI.