I created my own blog management system. Here's how I did it.
How I created a blog by building an API with Python and a webapp with VueJS and tackled meta related problems
I have had a personal blog for a while now. I had written a few posts there but it was far from perfect. It was built using basic HTML, CSS and JS. I had seen all this awesome sites with unique designs and I thought, why not create my own?
I went with a front-end for back-end approach which means the back-end needed to be robust in order for the content to load properly and fast.
I built my API using FastAPI for Python and the webapp using VueJS.
I laid down the endpoints that will possibly be needed in order for the blog to work properly.
Here are some of them
For the database, I went with mongoDB. So the idea is to store the posts as markdown in the database and let the API access it. The frontend will then just make a request and get all the data from the API.
It took me a few days to get the API ready. FastAPI was really helpful with their openapi docs to provide a nice interface in order to test the API without using curl
.
The posts and the subscribe endpoint are pretty self explanatory, here's how I created the related endpoint.
Since all the posts will have tags linked to them, I used those to calculate a score for the post.
The /related/<post_id>
endpoint was structered to pass a post_id
that would tell us which post to consider the root post. Once we have this post, we can fetch all the other posts and calculate a related score.
This score is calculated in the following way
# Consider root_tags are tags of the source post
# other_tags are the tags of the other post that.
def calculate(root_tags: List, other_tags: List) -> int:
# Remove duplicate tags if present
root_tags = set(root_tags)
other_tags = set(other_tags)
# Calculate the score now
score = len(root_tags.intersection(other_tags)) / len(root_tags)
return score
Above code does the following:
This way we get a score that would be between 0 and 1. Once we have this score, we can sort the posts based on the result and the posts that have a higher score are more related to a post as compared to other posts.
The webapp is built using VueJS. The whole idea of the frontend for backend approach is, the frontend will be dependent on the backend for the data.
Before building the app, I went through a few points that the app should be able to do
blog.com/nana
should load the post nana
and not just the webapp that is hosted on blog.com
)The first part is pretty simple. I just used the /posts
route in order to get all the posts and then displayed them in a nice way.
Here's the flow of how a post is rendered
The above basically does two things:
To pass the contents of the post by the route, use a route prop to pass a object that will hold the contents. In the Post view, check if this object is available or not, if not use the route to make a request and fetch the content.
Well yeah, I know SEO is important. For loading the meta tags I used vue-head which renders the meta tags dynamically after the post is loaded using the API.
This is pretty important since the meta tags are used by all the bots crawling the page. Also, Google bots are now able to crawl dynamically rendered content whcih means it should not be an issue if the tags are loaded dynamically using JS.
Except the common occurence of bugs, I did not had any problems with the back end. However there was one issue that made me question the whole idea. How do bots that do not have the ability to crawl dynamically rendered content crawl the page.
For example, twitter bots crawl a page in order to show a nice card view. If the bots are not able to crawl the page then the card won't be there. Not just Twitter, a similar functionality is used by various other social share bots like the ones from Facebook and LinkedIn.
Well, so how did I fix this issue? At first, I obviously thought this would be inevitable because there's no way the bots would be able to detect dynamically rendered content. One solution was to go with server side rendering but I'm better off not diving down that road.
So the solution that I went with was to write a static file server in Python.
What would our server do?
I built the server using Flask for Python. It detects the request making entity using the User-Agent
header being passed and accordingly returns an HTML. If the request is being made by a bot, it returns some HTML content that has the meta representing the post.
Else it returns the proper static files.
You can read about it here
Subscribe to get the latest posts. I mostly write about Backend (Python/MongoDB/Postgres), Frontend (Vue/Tailwind/SCSS) and Linux.
Discussion