#Balaur An app container for goji app
#Table of contents
#Usage NOTE You don't have to follow this structure, you are free to define your own structure, this structure is just my convention
For example I have a web app and it has 2 parts, user and blog, with balaur
it would be like this:
Structure
├── main.go
├── blog
│ ├── app.go
│ ├── controller.go
│ ├── middleware.go
│ ├── config.toml
│ ├── middlewares.toml
│ └── routes.toml
└── user
├── app.go
├── controller.go
├── middleware.go
├── config.toml
├── middlewares.toml
└── routes.toml
user app.go
should handle creation of user app and boot
the app (the same applies to blog
)
here's what the basic app should look like
package user
import (
"github.com/sendyhalim/balaur"
)
func init() {
var ctrl = &UserController{}
// 1st param is the directory path relative to your root app
// 2nd param is the configs (app, route, and middleware must be supplied)
// 3rd param is RouteRegistrar interface
// 4th param is MiddlewareRegistrar interface
// by default basic registrar will be created for you if you pass nil but of course you can create your own registrar
// as long as it conforms the interface
var app = balaur.NewApp("user", map[string]string{
"app": "config.toml",
"route": "routes.toml",
"middleware": "middlewares.toml",
}, nil, nil)
// register the controller, it will be mapped by route registrar
app.Controllers["user"] = ctrl
// register middlewares, the middleware will be registered for the app's parent route (set in routes.toml)
// app.Controller["authMiddleware"] = authMiddleware
// then in middlewares.toml:
// [[middleware]]
// key = "authMiddleware"
app.Boot()
}
App config (config.toml)
name = "User App"
routes config (routes.toml)
parent = "/*"
[[route]]
path = "/users"
verb = "GET"
controller = "user"
method = "Index"
[[route]]
path = "/users/:id"
verb = "GET"
controller = "user"
method = "Get"
User controller.go
package user
import (
"net/http"
"github.com/sendyhalim/balaur/context"
)
type UserController struct {
}
func (a *UserController) Index(c context.ContextInterface, r *http.Request) (string, int) {
return "User index!", http.StatusOK
}
func (a *UserController) Get(c context.ContextInterface, r *http.Request) (string, int) {
return "User id: " + c.GetParam("id"), http.StatusOK
}
then in main.go
package main
import (
_ "myproject/user"
_ "myproject/blog"
"github.com/sendyhalim/balaur"
"github.com/zenazn/goji"
)
func main() {
// balaur.GetApp(appName)
goji.Handle("/*", balaur.GetApp("User App").Mux)
goji.Handle("/*", balaur.GetApp("Blog App").Mux)
goji.Serve()
}
#Custom
##Route Registrar
You can inject your own route registrar by creating custom registrar and inject it(3rd param) when you use balaur.NewApp()
.
type RouteRegistrar interface {
// 1st param is goji Mux
// 2nd param is routes config (balaur already convert routes config as Config interface)
// 3rd param is the mapping of app controllers
RegisterRoutes(*web.Mux, []Config, map[string]interface{})
}
By creating your own custom route registrar, you can gain full flexibility on controller methods.
Here's balaur.BasicRouteRegistrar
code (full)
type ControllerMethod func(context.ContextInterface, *http.Request) (string, int)
type BasicRouteRegistrar struct {
// ControllerMethodWrapper is assigned when NewBasicRouteRegistrar() is called
ControllerMethodWrapper func(ControllerMethod) web.HandlerFunc
}
func (r *BasicRouteRegistrar) RegisterRoutes(mux *web.Mux, routes []Config, controllers map[string]interface{}) {
for _, config := range routes {
controller := config.Get("controller", true)
method := config.Get("method", true)
verb := config.Get("verb", true)
path := config.Get("path", true)
methodInterface := reflect.ValueOf(controllers[controller]).MethodByName(method).Interface()
methodValue := methodInterface.(func(context.ContextInterface, *http.Request) (string, int))
handler := r.ControllerMethodWrapper(methodValue)
switch verb {
case "GET":
mux.Get(path, handler)
case "POST":
mux.Post(path, handler)
case "PUT":
mux.Put(path, handler)
case "DELETE":
mux.Delete(path, handler)
}
}
}
As you can see by creating custom registrar, you can also modify controller methods type. If you only want to use different context (by default goji context is used), just do this
var routeRegistrar *BasicRouteRegistrar = balaur.NewBasicRouteRegistrar()
routeRegistrar.ControllerMethodWrapper = func(method balaur.ControllerMethod) web.HandlerFunc {
fn := func(c web.C, w http.ResponseWriter, r *http.Request) {
// as long as it conforms context.ContextInterface, then you can inject any
// custom context to BasicRouteRegistrar's ControllerMethod
response, code := method(&GorillaContext, r)
// do something else..
}
return web.HandlerFunc(fn)
}
// create app and inject routeRegistrar manually
var app = balaur.NewApp("user", map[string]string{
"app": "config.toml",
"route": "routes.toml",
"middleware": "middlewares.toml",
}, routeRegistrar, nil)
##Middleware Registrar
You can inject your own middleware registrar by creating custom registrar and inject it (4th param) when you use balaur.NewApp()
.
type MiddlewareRegistrar interface {
// 1st param is goji Mux
// 2nd param is middlewares config (balaur already convert middlewares config as Config interface)
// 3rd param is the mapping of app controllers
RegisterMiddlewares(*web.Mux, []Config, map[string]interface{})
}
BasicMiddlewareRegistrar
is really simple, it just maps the middleware config based on its index
type BasicMiddlewareRegistrar struct {}
func (r *BasicMiddlewareRegistrar) RegisterMiddlewares(mux *web.Mux, middlewareConfigs []Config, middlewares map[string]interface{}) {
for _, m := range middlewareConfigs {
key := m.Get("key", true)
mux.Use(middlewares[key])
}
}
- Better API documentation
- Scaffolding tools (automatic app generation e.g
balaur mkapp blog
then create the basic templates inside the given dir)
for now balaur
only use toml
as config, but it will support more config types in the future (such as json)
I will always improve and support this project as I'm using balaur
for most of my projects.