Golang Markdown Table
In this post we’re going to have a look at how to create a simple Markdown powered blog with Go(lang) and gin. The blog will be able to look up a markdown file by title / filename, display a list of all blog posts, display a single blog post and give the user an error page when a link can not be found.
Requirements:
Go is an open source programming language that makes it easy to build simple, reliable, and efficient software. Blackfriday Blackfriday is a Markdown processor implemented in Go. It is paranoid about its input (so you can safely feed it user-supplied data), it is fast, it supports common extensions (tables, smart punctuation substitutions, etc.), and it is safe for all utf-8 (unicode) input. Use the container list module for a linked list. Benchmark container list against slices. My contribution to the increasing entropy, and eventual heat death of the universe.
- You have Go installed
- You have (very) basic terminal command experience
Kids', toddler, & baby clothes with Google designs sold by independent artists. Shop high-quality t-shirts, masks, onesies, and hoodies for the perfect gift.
Setting up the Project Structure
The purpose of the blog is to render markdown files to good looking blog posts, so let’s create some directories and create our server file:
Now all the files that are going to be our blog posts go into markdown
, all template files:
index.tmpl.html
post.tmpl.html
error.tmpl.html
go into our templates directory.
The main.go
file is where our server code will live.
List posts and display on Index
Let’s go ahead and list all the markdown files we create in the markdown
directory, so an overview of all available posts if you will:
main.go
Let’s go through the file bit by bit:
- The
r.Delims()
function sets the characters we decide are the template tags that we’re going to use in our templates. - The
r.GET
function defines the route and will respond when/
so the root is accessed - We list the files of the directory with
ioutil.ReadDir
- We loop over the files and put the names into
posts
withappend
- We respond with
c.HTML
, rendering the index template and passing in theposts
string array
Next we’ll need an index.tmpl.html
file that looks something like this:
Noteworthy about this one is the template loop range
that will iterate over the posts. Since it’s a flat array {{ . }}
will display the string.
Let’s insert our first post, hello-world.md
in our markdown
directory. Insert what you like, I have made it:
Compiling Markdown to your Template
Next we want the links to work, so we want to display the individual (compiled) markdown files when somebody tries to access /hello-world.md
. For that purpose we’re going to make use of another third party library, blackfriday
The Post
struct is what we will populate with our Markdown before passing it on to the render function.
It contains a Title
and a Content
property. The title admittedly is not very useful right now, because it literally is the file name, but we’ll work on that later.
Let’s have a look at how a route could look when serving these MarkDown files to our blog readers:
The important parts of this route function are:
r.GET('/:postName'
enables us to use the name of the post inside our route:postName := c.Param('postName')
- we’re reading the contents of the markdown file with
ioutil.Readfile
and convert it to HTML withtemplate.HTML(blackfriday.MarkdownCommon([]byte(mdfile)))
- we’re responding with the error template and a
404
error if the file isn’t found - we’re inserting the compiled HTML into the
Post
struct
Now for the template, we’re going to duplicate the index template and change what’s in the class='container'
div:
Which will even make use of our… slightly filenamy title 🙂
Low let’s try to restart our gin server and click on the link on the front page.
You should be seen the content of your MarkDown file in HTML now. This is also the reason why we use the type template.HTML
, because we else would see the plain HTML, escaped and literally as the code and not the compiled version that gets interpreted by the browser.
Adding an 404 Error Page
So far, if we try to access, let’s say: http://localhost:8080/wombat
we get a blank page and also our server crashes. That’s because we have not created our error page yet, that we’re using in our blog post display route!
I’ve gone with the following error page template:
Using c.HTML(http.StatusNotFound, 'error.tmpl.html', nil)
also sends a 404 status code through HTTP.
Directly below that in our main.go
file we’re using return
which will cancel the execution of this gin context (request).
Adding Static Assets (Images and Stylesheets)
So far, so good, but what about images and stylesheets?
Luckily somebody wrote static asset serving as a middleware already: gin-contrib/static.
Importing 'github.com/gin-contrib/static'
will make it available and if we want to serve files from a directory called assets
, we can register the static files like this:
If we want to link images in our post we can now do:
If we want to use a stylesheet in the templates, we can reference them as:
Golang Markdown Renderer
Next Steps and Full Code
Thank you very much for reading! If you want to take your blog adventure further, you could try implementing the following things:
- Proper post titles
- Post dates
- Visitor count statistics
Golang Markdown Generator
Here’s the full example code for a very minimal golang blog web app:
Thank you for reading! If you have any comments, additions or questions, please leave them in the form below! You can also tweet them at me
If you want to read more like this, follow me on feedly or other rss readers