Link Search Menu Expand Document

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.

FrameworkDescriptionKey FeaturesPerformanceUse Cases
GinA lightweight web framework for building APIs.Fast, middleware support, JSON validation, routingHighRESTful APIs, microservices
FiberAn Express-inspired web framework for Go.Fast, minimalistic, middleware support, easy to useVery HighWeb applications, APIs, real-time apps
EchoA high-performance, extensible web framework.Middleware support, data binding, validationHighRESTful APIs, web applications
BeegoAn MVC framework for rapid development.Built-in ORM, RESTful support, admin interfaceModerateFull-stack applications, APIs
ChiA lightweight, idiomatic router for Go.Middleware support, composable routingHighMicroservices, 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{})
}