Beego Part 1 - MVC Web Development
One common use case for Go is web development. Typically, web development is done with a framework. Frameworks build some abstractions and tooling on top of base Go modules like net/http and html/template.
| Framework | Description | Key Features | Performance | Use Cases |
|---|---|---|---|---|
| Gin | A lightweight web framework for building APIs. | Fast, middleware support, JSON validation, routing | High | RESTful APIs, microservices |
| Fiber | An Express-inspired web framework for Go. | Fast, minimalistic, middleware support, easy to use | Very High | Web applications, APIs, real-time apps |
| Echo | A high-performance, extensible web framework. | Middleware support, data binding, validation | High | RESTful APIs, web applications |
| Beego | An MVC framework for rapid development. | Built-in ORM, RESTful support, admin interface | Moderate | Full-stack applications, APIs |
| Chi | A lightweight, idiomatic router for Go. | Middleware support, composable routing | High | Microservices, modular applications |
What is the MVC pattern?
Setup an MVC application with Beego
1. Installing Beego and Creating a Project
https://beegodoc.com/en-US/developing/#quick-start
Bee is a CLI for creating Beego applications.
go install github.com/beego/bee/v2@latest
# see if it worked
bee version
Create a project.
# create a project called "queenbee", it can be whatever name
bee new queenbee
cd queenbee
# this is the magic "make sure packages are installed" command
go mod tidy
2. Understanding the Project Structure
.
├── conf
│ └── app.conf
├── controllers
│ └── default.go
├── go.mod
├── go.sum
├── main.go
├── models
├── routers
│ └── router.go
├── static
│ ├── css
│ ├── img
│ └── js
│ └── reload.min.js
├── tests
│ └── default_test.go
└── views
└── index.tpl
11 directories, 9 files
Notice that Beego follows the MVC pattern, there are directories for models, views, and controllers. There is also a directory for the routers, which connect controllers and views to routes (paths in the URL).
Run the application with bee run.
Navigate the code structure to find where the HTML is coming from. Questions to answer:
- Where is the HTML?
- What ensures that file is served at the index path
/?
Add a Layout and Use Templates
We are going to take advantage of templating to make a layout that all pages can use. This will make sure they all have the same navbar, etc.
./views/layout.tpl
<!DOCTYPE html>
<html>
<head>
<title>{{ .Title }}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="{{.BaseUrl}}/static/css/output.css">
{{ block "css" . }}{{ end }}
</head>
<body>
<header>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</header>
<div>
{{ block "content" . }}{{ end }}
</div>
{{ block "js" . }}{{ end }}
</body>
</html>
./views/index.tpl - Change the file to have just this content.
{{ template "layout.tpl" . }}
{{ define "content" }}
<h2>{{ .Title }}</h2>
<p>Welcome to the Home Page!</p>
{{ end }}
Notice that the layout template has a block "content" section that will be later defined by each page that uses that template.
We also have a variable .Title that is expected from the server. With server-side rendering templates (common across many languages, not just Go), you can send data to the template from the controller.
./controllers/default.go
package controllers
import (
beego "github.com/beego/beego/v2/server/web"
)
type MainController struct {
beego.Controller
}
// TODO: modify the Get() http handler to render the "Title"
func (c *MainController) Get() {
// matches with {{ .Title }} in index.tpl and layout.tpl
c.Data["Title"] = "Home"
c.TplName = "index.tpl"
}
Adding Another Page
Challenge: How would you add an “About Page” at /about?
Show Answer (Controller)
Here is a possible solution.
./controllers/default.go
package controllers
import (
beego "github.com/beego/beego/v2/server/web"
)
type MainController struct {
beego.Controller
}
func (c *MainController) Get() {
c.Data["Title"] = "Home"
c.TplName = "index.tpl"
}
type AboutController struct {
beego.Controller
}
func (c *AboutController) Get() {
c.Data["Title"] = "About"
c.TplName = "about.tpl"
}
Show Answer (View)
Here is a possible solution.
./views/about.tpl
{{ template "layout.tpl" . }}
{{ define "content" }}
<h2>{{ .Title }}</h2>
<p>Welcome to the About Page!</p>
{{ end }}
Show Answer (Router)
Here is a possible solution.
./routers/router.go
package routers
import (
"queenbee/controllers"
beego "github.com/beego/beego/v2/server/web"
)
func init() {
beego.Router("/", &controllers.MainController{})
beego.Router("/about", &controllers.AboutController{})
}