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

от автора

Привет, Хабр!

Beego – это фреймворк для разработки веб-приложений на языке Go, ориентированный на быстрое развертывание и простоту использования. В его основе лежит идея создания полнофункциональных приложений с минимум усилиям на настройку и кодирование. Это достигается за счет широкого выбора инструментов, включая ORM, систему маршрутизации, интерфейс кмд и многое другое. 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 упрощает стандартные задачи в создание веб-приложений.

Больше про языки программирования эксперты OTUS рассказывают в рамках практических онлайн-курсов. С полным каталогом курсов можно ознакомиться по ссылке.


ссылка на оригинал статьи https://habr.com/ru/articles/802333/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *