Personal Blog by Golang

logos.jpg?w=2924

Why

I used to use Wordpress to write my blog. But I recently think of creating the blog system by Golang and make it for fun. Here is what I am doing now. The main reason I start doing is that I found the markdown support in Wordpress is slightly weird and hard to use. When I try to change some blog content, the markdown style sometimes won’t show correctly. That makes me feel frustrated. I think that probably might because I am using the free plan in wordpress.com and have less control of my blog.

So, my goal is quite simple and straightforward. The new blog should fully support markdown content. And it should serve a clean and straightforward interface. Let’s see how I am going to do it.

Due to the two goals above, here I choose to create it from scratch. I choose to use Go-Gin and Blackfriday to build the blog system.

quote-talk-is-cheap-show-me-the-code-linus-torvalds-273528.jpg

Do it

Go Gin

Gin is an HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance – up to 40 times faster.

Blackfriday

Blackfriday: a markdown processor for Go.

These two libraries give me enough abilities to build the blog system.

The first step, create your blog folders with two sub-folder, markdowns, and templates. Markdowns folder is for your blog content post. Templates folder is for the HTML template, which we load posts list and content into an HTML page.

Let’s check HTML template files first.

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Chauyan's Murmur</title>
<link href="dark_theme.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div class="container">
<ul>
{{ range .posts }}
<li>
<a href="/{{ . }}">{{ . }}</a>
</li>
{{ end }}
</ul>
</div>
</body>
</html>

It’s pretty simple. It’s just a simple home page with a list of web posts. You can see the

1
{{ }}

buckets wrapped in the template, which is the action in the template by module html/template in Go.

post.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>{{.Title}}</title>
<link href="dark_theme.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div class="container">
{{.Content}}
</div>
</body>
</html>

error.html - 404 not found page

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>We've got some trouble | 404 - Resource not found</title>
<link href="dark_theme.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div class="cover">
<h1>Resource not found
<small>Error 404</small>
</h1>
<p class="lead">The requested resource could not be found but may be available again in the future. <a href="/">Go back now!</a></p></div>
<footer><p>Technical Contact: <a href="wang.chauyan@gmail.com">e-mail me</a></p></footer>
</body>
</html>

Gin would load these template files into our primary function. Let’s take a look of the main.go source code here.

main.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package main

import (
"fmt"
"github.com/gin-gonic/gin"
"gopkg.in/russross/blackfriday.v2"
"html/template"
"io/ioutil"
"log"
"net/http"
"os"
)

const markdownPath = "./markdowns/"
const templatePath = "./templates/"

type Post struct {
Title string
Content template.HTML
}

func initServer() *gin.Engine {
server := gin.Default()
server.Use(gin.Logger())
server.Delims("{{", "}}")

// load html template files
server.LoadHTMLGlob(templatePath + "*.html")

return server
}

func setupRootAPI(server *gin.Engine) {
// handle the root access
server.GET("/", func(c *gin.Context) {
var posts []string

files, err := ioutil.ReadDir(markdownPath)
if err != nil {
log.Fatal(err)
}

for _, file := range files {
fmt.Println(file.Name())
posts = append(posts, file.Name())
}

c.HTML(
http.StatusOK,
"index.html",
gin.H {"posts": posts,}
)
})
}

func setupPostAPI(server *gin.Engine) {
server.GET("/:postName", func(c *gin.Context) {
postName := c.Param("postName")

mdfile, err := ioutil.ReadFile(markdownPath + postName)

if err != nil {
fmt.Println(err)
// handle the error page access
c.HTML(http.StatusNotFound, "error.html", nil)
c.Abort()
return
}

postHTML := template.HTML(blackfriday.Run([]byte(mdfile)))

post := Post{Title: postName, Content: postHTML}

c.HTML(
http.StatusOK,
"post.html",
gin.H{
"Title": post.Title,
"Content": post.Content,
}
)
})
}


func main() {
server := initServer()

// setup home API
setupRootAPI(server)

// handle the post access
setupPostAPI(server)

server.Run(":" + os.Args[1])
}

Functionality

Let’s check the main function first. We have 4 steps to run this blog system:

  • initServer to initialize the Gin engine to get the instance back. In the meantime, we also tell Gin how we load the templates and use actions.
  • setupRootAPI to set up how to react with users access your homepage entry point.
  • setupPostAPI to set up how to send back the selected post content back to the user.
  • server.Run to run up the server-side.

It’s pretty straightforward and easy to understand. I think the next step I would need to have the theme support in this simple blog system like
Ghost Themes. You can find the whole project in my Github repo - Mini blog system in Go

Happy coding. Enjoy.