Beego в Golang для начинающих

Kate

Administrator
Команда форума
Beego – это фреймворк для разработки веб-приложений на языке Go, ориентированный на быстрое развертывание и простоту использования. В его основе лежит идея создания полнофункциональных приложений с минимум усилиям на настройку и кодирование. Это достигается за счет широкого выбора инструментов, включая ORM, систему маршрутизации, интерфейс кмд и многое другое. Beego придерживается принципов RESTful и MVC.

Установим и создадим первый проект​

Установить Beego проще пареной репы:

go get -u github.com/beego/beego/v2
Команда загрузит Beego и добавит его в рабочую директорию GOPATH.

Также потребуется установить Bee от создателей Beego, который является инструментом командной строки:

go get -u github.com/beego/bee/v2
После установки Beego и Bee можно уже приступать к работе.

В терминале переходим в директорию, где хочется разместить новый проект, и выполняем команду:

bee new <имя_проекта>
После создания проекта, в директории проекта можно увидеть стандартную структуру каталогов Beego:

controllers — для файлов контроллеров

models — для моделей данных

routers — для настройки маршрутов

views — для шаблонов представлений

main.go — точка входа в приложение

Запуск выглядит достаточно просто:

bee run
Так запустим веб-сервер на localhost с портом по умолчанию 8080 и можно увидеть результаты работы приложения, перейдя по адресу http://localhost:8080 в браузере.

Работа с роутером​

Маршрутизация в Beego определяется в файле routers/router.go. В этом файле можно указать какие контроллеры должны обрабатывать различные URL-пути. Beego поддерживает статическую и параметризованную маршрутизацию, а также группировку маршрутов. Например, пример статической маршрутизации:

package routers

import (
"myapp/controllers"
"github.com/beego/beego/v2/server/web"
)

func init() {
web.Router("/", &controllers.MainController{})
}
Для обработки запросов к корню сайта / используется MainController.

Пример параметризованной маршрутизации:

web.Router("/user/:id", &controllers.UserController{})
Для обработки запросов к /user/123, где 123 — это динамический параметр id, используется UserController.

Контроллеры в Beego наследуются от beego.Controller и содержат методы, соответствующие HTTP-методам Get, Post, Delete и т.д., которые вызываются при обращении к связанным с ними маршрутам. Пример контроллера:

package controllers

import "github.com/beego/beego/v2/server/web"

type MainController struct {
web.Controller
}

func (c *MainController) Get() {
c.Data["Website"] = "Beego.me"
c.Data["Email"] = "contact@beego.me"
c.TplName = "index.tpl"
}
MainController обрабатывает GET-запросы. Данные, передаваемые в представление index.tpl, устанавливаются через c.Data.

Beego позволяет настраивать маршруты гибче, используя функцииweb.NSRouter, web.Include, и web.NSNamespace для группировки маршрутов и в целом более удобной организации приложений.

Пример группировки маршрутов:

ns := web.NewNamespace("/v1",
web.NSRouter("/user", &controllers.UserController{}, "get:ListUsers"),
web.NSRouter("/user/:id", &controllers.UserController{}, "get:GetUser"),
)

web.AddNamespace(ns)
Создали пространство имен /v1, в котором группируются маршруты, относящиеся к пользователям.

Также существуют перехватчики, которые позволяют выполнять код до или после определенных контроллеров:

web.InsertFilter("/user/*", web.BeforeExec, InterceptorFunc)
InterceptorFunc будет вызываться перед каждым выполнением методов контроллера, обрабатывающего пути, соответствующие шаблону /user/*.

Также есть механизм авто-роутинга, который автоматически связывает URL-адреса с методами контроллеров на основе их имен:

web.AutoRouter(&controllers.YourController{})
Так Beego будет автоматически маршрутизировать запросы типа /yourcontroller/methodname к соответствующим методам в YourController.

Для решения более специфических задач, связанных с маршрутизацией, Beego позволяет настраивать роутер с помощью регулярных выражений и условий:

web.Router("/user/:id([0-9]+)", &controllers.UserController{})
Запросы к /user/123 будут обрабатываться UserController, при этом :id должен соответствовать регулярному выражению [0-9]+, что означает одну или более цифр.

Beego суперски подходит для создания RESTful API благодаря своей системе маршрутизации. Можно определить маршруты для каждого из HTTP-методов (GET, POST, PUT, DELETE и т.д.) и связать их с соответствующими методами в контроллерах:

web.Router("/api/user", &controllers.UserController{}, "get:GetUsers;post:CreateUser")
web.Router("/api/user/:id", &controllers.UserController{}, "get:GetUser;put:UpdateUser;delete:DeleteUser")
Используя перехватчики, авто-роутинг, кастомные пути с регулярными выражениями и поддержку RESTful URL, можно идеально управлять потоками.

Работа с БД​

ORM Beego позволяет отображать таблицы БД на структуры Go, превращая строки таблиц в объекты Go.

Подключение к БД на примере MySQL​

Установим:

go get -u github.com/go-sql-driver/mysql
В файле конфигурации приложения Beego conf/app.conf указываем параметры подключения к MySQL:

[database]
dbDriver = mysql
dbUser = ваш_пользователь
dbPass = ваш_пароль
dbName = имя_базы_данных
dbHost = 127.0.0.1
dbPort = 3306
В приложении (например, в main.go) юзаем информацию из конфига для инициализации подключения к БД:

import (
"github.com/beego/beego/v2/client/orm"
_ "github.com/go-sql-driver/mysql"
)

func init() {
orm.RegisterDriver("mysql", orm.DRMySQL)
// строка подключения: пользователь:пароль@tcp(хост:порт)/имя_базы_данных
orm.RegisterDataBase("default", "mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
}
Прочие БД подключаются аналогично.

Определение моделей​

Для взаимодействия с БД понадобится определить модели. В Beego модели — это структуры Go, которые отражают структуру таблиц в базе данных. Пример простой модели пользователя:

type User struct {
Id int
Name string
Password string
}
Чтобы использовать эту модель в Beego ORM её нужно зарегистрировать в системе ORM. Это делается так:

func init() {
orm.RegisterModel(new(User))
}
После настройки подключения к БД и определения моделей можно приступить к операциям с данными.

Чтобы создать новую запись в базе данных, используем Insert объекта ORM:

o := orm.NewOrm()
user := User{Name: "ivan", Password: "securepassword"}

id, err := o.Insert(&user)
if err != nil {
// обработка ошибки
}
Для чтения есть метод Read:

o := orm.NewOrm()
user := User{Id: 1}

err := o.Read(&user)
if err == orm.ErrNoRows {
// зЗапись не найдена
} else if err == nil {
// запись найдена, `user` заполнен данными
}
Для обновления записи апдейт:

o := orm.NewOrm()
user := User{Id: 1, Name: "ivan Updated"}

_, err := o.Update(&user, "Name")
if err != nil {
// обработка ошибки
}
Для удаления записи Delete:

o := orm.NewOrm()
user := User{Id: 1}

_, err := o.Delete(&user)
if err != nil {
// обработка ошибки
}
Также есть транзакции, составные запросы, ленивая загрузка и т.д. Например, для выполнения транзакции:

o := orm.NewOrm()
err := o.Begin()

user := User{Name: "Ivan Transaction", Password: "transpassword"}
_, err = o.Insert(&user)
if err != nil {
o.Rollback()
} else {
o.Commit()
}
Также Beego ORM поддерживает работу с запросами через QueryBuilder:

var users []User
qb, _ := orm.NewQueryBuilder("mysql")
qb.Select("id", "name").From("user").Where("id > ?").OrderBy("id").Desc().Limit(10)
orm.NewOrm().Raw(qb.String(), 1).QueryRows(&users)

Создание пользовательского интерфейса​

Beego использует систему шаблонов Go html/template для динамической генерации HTML. Шаблоны позволяют разделять логику приложения и его представление.

Шаблоны обычно хранятся в каталоге views и имеют расширение .tpl или .html. В шаблонах можно использовать конструкции Go Template для вставки данных, выполнения условий и циклов:

<!-- views/index.tpl -->
<html>
<body>
<h1>{{.Title}}</h1>
{{range .Items}}
<div>{{ . }}</div>
{{else}}
<div>No items found.</div>
{{end}}
</body>
</html>
В контроллерах Beego можно передавать данные в шаблон, используя мапу Data.

func (this *MainController) Get() {
this.Data["Title"] = "My Page Title"
this.Data["Items"] = []string{"Item 1", "Item 2", "Item 3"}
this.TplName = "index.tpl"
}
Beego автоматически компилирует шаблоны и рендерит их при вызове метода ServeHTTP. Имя шаблона указывается в свойстве TplName контроллера.

Также есть возможность локализации с помощью поддержки i18n в пакете github.com/beego/beego/v2/server/web/i18n.

Файлы локализации хранятся в формате INI или JSON и содержат пары ключ-значение для переводов. По дефолту они размещаются в каталоге conf/locale:

// conf/locale/en-US.ini
hello = "Hello"

// conf/locale/ru-RU.ini
hello = "Привет"
В main.go или в начальной функции приложения можно инициализровать i18n и указать директорию с файлами локализации:

import "github.com/beego/beego/v2/server/web"

func init() {
web.SetStaticPath("/static", "static")
web.AddFuncMap("i18n", web.I18n)
web.LoadAppConfig("ini", "conf/app.conf")
if err := web.LoadI18n("conf/locale"); err != nil {
log.Fatal("Failed to load i18n files:", err)
}
}
Для использования локализации в шаблонах можно юзать функцию i18n.Tr.

<body>
<h1>{{i18n.Tr "en-US" "hello"}}</h1>
</body>
И в контроллерах можно использовать ту же функцию для получения локализованных строк программно:

codefunc (this *MainController) Get() {
locale := "ru-RU" // Обычно это значение извлекается из настроек пользователя или заголовков запроса
greeting := web.I18n(locale, "hello")
this.Data["Greeting"] = greeting
this.TplName = "index.tpl"
}
Язык для пользователя обычно определяется автоматически на основе заголовков HTTP-запроса, но его также можно задать явно, например, в зависимости от выбора пользователя на сайте.

Тестирование​

Тесты в Beego по дефолту размещаются в папке tests проекта.

Допустим, у нас есть контроллер MainController с методом Get, который возвращает простое сообщение. Пример теста для этого метода:

Определение контроллера:

// controllers/main.go
package controllers

import (
"github.com/beego/beego/v2/server/web"
)

type MainController struct {
web.Controller
}

func (c *MainController) Get() {
c.Ctx.WriteString("Hello, Beego!")
}
Создаем файл теста в папке tests, например, main_test.go:

// tests/main_test.go
package test

import (
"net/http"
"net/http/httptest"
"testing"
"github.com/beego/beego/v2/server/web"
"path/filepath"
"runtime"
_ "yourapp/routers"

"github.com/stretchr/testify/assert"
)

func init() {
_, file, _, _ := runtime.Caller(0)
apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".." + string(filepath.Separator))))
web.TestBeegoInit(apppath)
}

func TestMainPage(t *testing.T) {
r, _ := http.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
web.BeeApp.Handlers.ServeHTTP(w, r)

assert.Equal(t, 200, w.Code)
assert.Equal(t, "Hello, Beego!", w.Body.String())
}
Юзаем пакет assert библиотеки testify для проверки, что ответ от сервера соответствует ожиданиям. Создаем HTTP-запрос к главной странице и проверяем, что статус-код ответа равен 200 и тело ответа содержит "Hello, Beego!".

Тесты в Beego, как и в любом Go-приложении, можно запустить с помощью команды go test:

go test ./...
Команда рекурсивно найдет и выполнит все тесты в вашем проекте Beego.

А вот для тестирования API можно использовать пакет httptest. Предположим, есть API для получения информации о пользователях.

Пример контроллера API:

// controllers/user.go
package controllers

import (
"encoding/json"
"github.com/beego/beego/v2/server/web"
)

type UserController struct {
web.Controller
}

func (c *UserController) GetUser() {
userId := c.Ctx.Input.Param(":id")
user := User{Id: userId, Name: "Test User"}

c.Data["json"] = &user
c.ServeJSON()
}

type User struct {
Id string `json:"id"`
Name string `json:"name"`
}
Пример теста API:

// tests/api_test.go
package test

import (
"bytes"
"net/http"
"net/http/httptest"
"testing"
_ "yourapp/routers"

"github.com/stretchr/testify/assert"
)

func TestGetUser(t *testing.T) {
req, err := http.NewRequest("GET", "/user/1", nil)
if err != nil {
t.Fatal(err)
}

rr := httptest.NewRecorder()
web.BeeApp.Handlers.ServeHTTP(rr, req)

assert.Equal(t, http.StatusOK, rr.Code)

expected := `{"id":"1","name":"Test User"}`
assert.Equal(t, expected, strings.TrimSpace(rr.Body.String()))
}
Создаем HTTP GET запрос к нашему API /user/1 и проверяем, что статус код ответа 200 OK и тело ответа соответствует ожидаемому JSON-объекту.

При тестировании компонентов, взаимодействующих с БД, нужно изолировать тесты от реальной БД. Это можно сделать с помощью мокинга или настройки тестовой БД:

func init() {
orm.RegisterDataBase("default", "sqlite3", "file::memory:?mode=memory&cache=shared", 30)
}
Юзаем SQLite в памяти для создания изолированной тестовой среды.

func TestCreateUser(t *testing.T) {
o := orm.NewOrm()
o.Using("default") //

user := &User{Name: "New User"}
id, err := o.Insert(user)
if err != nil {
t.Errorf("Не удалось создать пользователя: %v", err)
}

assert.NotEqual(t, 0, id)
}
Вставляем нового пользователя в тестовую БД и проверяем, что операция вставки прошла успешно, а возвращаемый идентификатор пользователя не равен нулю.

Прочие возможности​

Работа с сессиями и куками​

В Beego сессии активируются в файле конфигурации app.conf с использованием параметров sessionon, sessionprovider, и sessionname. Пример конфигурации для активации сессий:

sessionon = true
sessionprovider = "memory"
sessionname = "beegosessionID"
После активации, сессии можно использовать прямо в контроллерах:

func (c *MainController) AnyMethodName() {
// установка значения сессии
c.SetSession("key", "value")

// получение значения сессии
value := c.GetSession("key")

// удаление значения сессии
c.DelSession("key")

// уничтожение сессии
c.DestroySession()
}
Работа с куками также предельно упрощена:

func (c *MainController) AnyMethodName() {
// установка куки
c.Ctx.SetCookie("name", "value", expire)

// чтение куки
value := c.Ctx.GetCookie("name")
}

Логирование​

Настройка:

logs.SetLogger(logs.AdapterFile, `{"filename":"log/myapp.log"}`)
logs.SetLevel(logs.LevelInfo)
Настраивает логирование в файл с определенным уровнем логирования.

Beego позволяет определять спец. методы обработки ошибок в контроллерах:

func (c *MainController) Error404() {
c.Data["content"] = "Page not found"
c.TplName = "404.tpl"
}

Автоматическая генерация документации API​

Beego интегрирован с Swagger, позволяя автоматически генерировать документацию для API. Для этого необходимо использовать комментарии к коду и инструмент bee для генерации документации:

// @Title Get User
// @Description get user by uid
// @Param uid path int true "The key for staticblock"
// @Success 200 {object} User
// @Failure 403 :uid is empty
// @router /:uid [get]
func (u *UserController) Get() {
// реализация метода
}
Используя команду bee run -gendoc=true -downdoc=true, можно сгенерировать документацию Swagger, которая будет доступна по адресу /swagger приложения.


Beego упрощает стандартные задачи в создание веб-приложений.

 
Сверху