Веб приложение с Beego
Это перевод статьи от Matthew Setter. Оригинал на sitepoint.com
Введение
Вы веб-девелопер, пришедший к Go с динамических языков программирования, таких как: PHP, Python, Ruby и хотите узнать, как использовать этот самый Go для разработки веба? Вам интересно узнать, как разрабатывать на Go в привычной для вас манере ваших любимых фреймворков, используя свой накопленный опыт?
Если это так, значит вы уже искали в гугле, на StackOverflow и других сайтах фреймворки, которые могут вам помочь. И вы наверняка видели такие названия как Beego, Martini и Gorilla. А также, пакет net/http.
Из этих четырех фреймворков я больше всего экспериментировал с Beego. Я обнаружил, что это многофункциональный и притом не очень сложный инструмент, который позволяет очень быстро начать разрабатывать веб-сайты.
Beego не даст вам сразу таких же результатов, как ваши используемые фреймворки. Да, в beego много готовых батареек и различных пакетов, таких как:
- Полноценная ORM
- Кеш
- Работа с сессиями
- Интернационализация (i18n)
- Мониторинг и перегрузка приложения при разработке
- Инструменты для деплоя
Но, несмотря на существующие сходства, этот фрейморк очень сильно отличается от всех уже известных вам, написанных на динамических языках. И вам прийдётся потратить некоторое временя, чтобы Beego стал действительно продуктивным инструментом.
Кроме того, хоть документация по фреймворку достаточно полная, создается ощущения пропущенных пунктов то там, то тут. Поэтому, я решил написать серию из двух статей, которые помогут вам понять эти нюансы и научиться основам Beego.
Из этой серии вы узнаете, насколько это чудесный фреймворк, и как он сможет облегчить нам работу. Конкретно, в первой части я раскрою такие темы:
- Установка и использование консольной утилиты
- Создание проекта
- Экшены(Действия, Actions)
- Представления и Шаблоны(Views)
- Роутинг
- Параметры запроса
Если вы хотите почитать полный код всех примеров из этих статей, то он доступен на GitHub. Вас никто не ограничивает в копировании и экспериментировании с этим кодом. Let’s Go!
Перед тем, как мы начнем, убедитесь что у вас правильно настроено Go окружение. Если это не так или вы не уверены, посмотрите статьи "Getting Started with Go" или этот пост от Bill Kennedy, после этого мы сможем продолжить.
Установка Beego
Окей, давайте начнем с установки Beego. Как и многие другие фреймворки, beego имеет встроенные инструменты для скафолдинга, к которым можно добраться используя консольную команду bee
. Эта команда умеет:
- Создание нового приложения
- Запуск приложения
- Тестирование приложения
- Создание роутов и многое другое
Bee это не единственный путь для запуска приложения, но мы будем использовать только его в этих двух статьях. Для установки запустите команду go get github.com/beego/bee
Создание основного проекта
После установки выполните команду из $GOPATH
, которая создаст скелет приложения с названием sitepointgoapp:
bee new sitepointgoapp
На экране должно быть что-то похожее на это:
[INFO] Creating application...
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/conf/
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/controllers/
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/models/
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/routers/
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/tests/
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/static/
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/static/js/
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/static/css/
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/static/img/
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/views/
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/conf/app.conf
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/controllers/default.go
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/views/index.tpl
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/routers/router.go
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/tests/default_test.go
/Users/matthewsetter/Documents/workspace/Golang/src/sitepointgoapp/main.go
14-05-14 06:02:59 [SUCC] New application successfully created!
Можете посмотреть на созданную структуру проекта
sitepointgoapp
├── conf
│ └── app.conf
├── controllers
│ └── default.go
├── main.go
├── models
├── routers
│ └── router.go
├── static
│ ├── css
│ ├── img
│ └── js
├── tests
│ └── default_test.go
└── views
└── index.tpl
Давайте посмотрим, какие файлы у нас получились
- Наш стартовый файл
main.go
- Основной конфигурационный файл
conf/app.conf
- Дефольный контроллер
controllers/default.go
- Тесты к нашему контролеру
tests/default_test.go
- Дефолтный темплейт
views/index.tpl
Базовое приложение готово. Давайте его запустим. Из директории проекта $GOPATH/src/sitepointgoapp/
выполним следующую команду:
bee run
Теперь, наше приложение запушено. Одно из преимуществ bee - это мониторинг изменения файлов. Если есть какие-нибудь изменения, bee перезагружает приложение автоматически. После выполнения команды, вы должны увидеть примерно такой вывод.
14-05-05 11:34:17 [INFO] Start building...
14-05-05 11:34:20 [SUCC] Build was successful
14-05-05 11:34:20 [INFO] Restarting sitepointgoapp ...
14-05-05 11:34:20 [INFO] ./sitepointgoapp is running...
2014/05/05 11:34:20 [I] Running on :8080
Как видно, приложение запущенно на 8080 порту. Перейдем по адресу http://localhost:8080/
в браузере и увидим такую страничку:
Ничего вызывающего, но это работает. И так, засучим рукава и расширим возможности дефолтного контроллера, добавив новый экшен с каким-нибудь кастомным роутом.
Добавление нового экшена
Откройте файл controllers/default.go
вы увидите хорошо структурированный контроллер. Все, что связано с рендерингом убрано в шаблоны представления. Давайте немного изменим код и посмотрим, как добавлять новые переменные в шаблоны и работать с этими шаблонами. В default.go
добавим еще одни метод:
func (main *MainController) HelloSitepoint() {
main.Data["Website"] = "My Website"
main.Data["Email"] = "your.email.address@example.com"
main.Data["EmailName"] = "Your Name"
main.TplNames = "default/hello-sitepoint.tpl"
}
Давайте разберем, что это все обозначает. Мы добавили новый GET
метод (экшен) в контроллере указав main *MainController
.
У нас есть три инициализированных переменных представления Website
, Email
и EmailName
, записанные в поле контроллера Data
, которое является мапом и хранит все переменные представления.
После этого, я указал имя шаблона default/hello-sitepoint.tpl
в поле main.TplNames
. Нужно заметить, что по умолчанию Beego ищет файлы шаблонов в папке views
И так, когда будет запрошен наш роут, Beego найдет указанный файл шаблона и отрендерит его.
Представления
Давайте создадим соответствующий шаблон представления. В директории views
создайте подкаталог default
и в нем файл hello-sitepoint.tpl
с таким кодом:
<header class="hero-unit">
<div class="container">
<div class="row">
<div class="hero-text">
<h1>Welcome to the Sitepoint / Beego App!</h1>
<h2>This is My Test Version</h2>
<p>{{.Website}} {{.Email}} {{.EmailName}}</p>
</div>
</div>
</div>
</header>
Если это ваше первое знакомство с шаблонами в Go, имейте в виду, что Beego расширяет стандартный пакет html/template. Можете посмотреть хорошие примеры использования переменных в шаблонах из пакета text/template.
Как и многие другие Go пакеты html/template достаточно обширен, поэтому я расскажу только про интересующие нас возможности. Все переменные в шаблонах доступны при использовании оператора точки и фигурных скобок {{}}
Значит, чтобы добраться до наших переменных, установленных ранее в контроллере, нам нужно использовать конструкции {{.Website}}
, {{.Email}}
, и {{.EmailName}}
Роутинг
Окей, у нас есть экшн и привязанный к нему шаблон представления. Но мы все еще не можем зайти на страничку. Если мы попробуем добраться до чего-угодно, кроме дефолтного экшена, то увидим 404 ошибку.
Это значит, что нам нужно добавить роут в файл routers/router.go
. Добавляем код в метод init()
func init() {
beego.Router("/", &controllers.MainController{})
beego.Router("/hello-world", &controllers.MainController{}, "get:HelloSitepoint")
}
Обратите внимание на последнюю строчку этого файла. HelloSitepoint
экшен, который мы только что добавили контроллеру MainController
, привязывается к /hello-world. Сохраняем все это, ждем минуту, пока проект перекомпилируется, и открываем http://localhost:8080/hello-world
в браузеер. Если все правильно сделано, то страничка должна быть такой:
Параметры запроса
К этому моменту у нас есть готовый простой экшен. Но в реальном мире приложение должно взаимодействовать с пользователем данных из POST и/или строки запроса(GET) и возвращать соответствующий результат. Как нам получить доступ к этой информации в Beego?
Давайте начнем с строки запроса. Одно из предустановленных значений в Beego это модуль контекста(Context Module), который инкапсулирует запрос содержащий входящие значения.
Этот модуль дает нам доступ к таким свойствам запроса:
- Метод/hello-world/213
- Протокол
- Юзер агент
- Запрос(данные из GET/POST)
- Сессии и многое другое
Давайте сделаем наше приложение более интересным и добавим в роут id параметр, которые мы сможем получить в нашем экшене. Для этого в файле router.go
нужно изменить наш код.
beego.Router("/hello-world/:id([0-9]+)", &controllers.MainController{}, "get:HelloSitepoint")
При обращении по этому роуту мы должны передать GET значание, которое может быть только числом, так как в определении роута используется регулярное выражение ([0-9]+)
. Попробуйте перейти по адресу /hello-world
без указания id. Видите ошибку?
А если перейти по /hello-world/213
, то наша страница отобразится правильно, без всяких ошибок. Теперь можем получить id в нашем экшене. Для этого, перед main.TplNames
добавим:
main.Data["Id"] = main.Ctx.Input.Param(":id")
И в шаблоне hello-world.tpl
добавим {{.Id}}
после уже существующих переменных. Обновим страницу и увидим значение 213 после Email Name.
Разделение экшенов по методу запроса
Мы почти закончили на сегодня, но я хочу раскрыть одну вещь, прежде чем закончить. Довольно часто бывает необходимым ограничить доступ к действию в зависимости от метода запроса. Например, логично, чтобы экшен добавления сущности работал только при POST запросе, а экшен получения списка сущностей только при GET запросе.
Beego позволяет очень просто разделять доступы для экшенов в зависимости от метода запроса. В файле с роутами router.go
снова измените роут /hello-world
как показано ниже:
beego.Router("/hello-world/:id([0-9]+)", &controllers.MainController{}, "get,post:HelloSitepoint")
Строчка get,post:HelloSitepoint
означает, что экшен HelloSitepoint
будет отрабатывать только при GET или POST запросе. Давайте попробуем обратиться по /hello-world/
используя DELETE или PUT.
# PUT request
curl -X PUT http://localhost:8080/hello-world/213
# DELETE request
curl -X DELETE http://localhost:8080/hello-world/213
Заключение
Надеюсь, вам понравилось это введение в разработку на Beego фреймворке. Во второй части мы рассмотрим использование баз данных(SQLite3), модели, формы и валидацию.
К концу второй части у нас будет готово приложение со всеми основными функциями, которые будут использоваться изо дня в день.
Несмотря на то, что Beego и Go сильно отличаются от динамических языков программирования, которые вы использовали ранее, потратив немного времени, вы сможете использовать всю мощь фреймворка.
Не забывайте, весь код доступен на GitHub. Можете склонировать репозиторий и экспериментировать с ним.
Что вы думаете об этом всем? Достаточно ли этого материала для старта использования Go, или еще нет? Поделитесь своими мыслями в комментариях.
Ссылки
- http://www.goinggo.net/2013/06/installing-go-gocode-gdb-and-liteide.html
- https://groups.google.com/forum/#!topic/golang-nuts/hbNCHMIA05g
- http://stackoverflow.com/questions/10105935/how-to-convert-a-int-value-to-string-in-go
- http://beego.me/
- https://github.com/astaxie/beego
- http://golang.org/pkg/text/template/
- http://golang.org/doc/effective_go.html
- http://blog.golang.org/go-maps-in-action