a golang web mvc framework, like asp.net mvc.

Overview

goku

goku is a Web Mvc Framework for golang, mostly like ASP.NET MVC.

doc & api

Installation

To install goku, simply run go get github.com/QLeelulu/goku. To use it in a program, use import "github.com/QLeelulu/goku"

To run example "todo" app, just:

$ cd $GOROOT/src/pkg/github.com/QLeelulu/goku/examples/todo/
$ go run app.go

maybe you need run todo.sql first.

Usage

package main

import (
    "github.com/QLeelulu/goku"
    "log"
    "path"
    "runtime"
    "time"
)

// routes
var routes []*goku.Route = []*goku.Route{
    // static file route
    &goku.Route{
        Name:     "static",
        IsStatic: true,
        Pattern:  "/static/(.*)",
    },
    // default controller and action route
    &goku.Route{
        Name:       "default",
        Pattern:    "/{controller}/{action}/{id}",
        Default:    map[string]string{"controller": "home", "action": "index", "id": "0"},
        Constraint: map[string]string{"id": "\\d+"},
    },
}

// server config
var config *goku.ServerConfig = &goku.ServerConfig{
    Addr:           ":8888",
    ReadTimeout:    10 * time.Second,
    WriteTimeout:   10 * time.Second,
    MaxHeaderBytes: 1 << 20,
    //RootDir:        os.Getwd(),
    StaticPath: "static",
    ViewPath:   "views",
    Debug:      true,
}

func init() {
    /**
     * project root dir
     */
    _, filename, _, _ := runtime.Caller(1)
    config.RootDir = path.Dir(filename)

    /**
     * Controller & Action
     */
    goku.Controller("home").
        Get("index", func(ctx *goku.HttpContext) goku.ActionResulter {
        return ctx.Html("Hello World")
    })

}

func main() {
    rt := &goku.RouteTable{Routes: routes}
    s := goku.CreateServer(rt, nil, config)
    goku.Logger().Logln("Server start on", s.Addr)
    log.Fatal(s.ListenAndServe())
}

Route

var Routes []*goku.Route = []*goku.Route{
    &goku.Route{
        Name:     "static",
        IsStatic: true,
        Pattern:  "/public/(.*)",
    },
    &goku.Route{
        Name:       "edit",
        Pattern:    "/{controller}/{id}/{action}",
        Default:    map[string]string{"action": "edit"},
        Constraint: map[string]string{"id": "\\d+"},
    },
    &goku.Route{
        Name:    "default",
        Pattern: "/{controller}/{action}",
        Default: map[string]string{"controller": "todo", "action": "index"},
    },
}
// create server with the rules
rt := &goku.RouteTable{Routes: todo.Routes}
s := goku.CreateServer(rt, nil, nil)
log.Fatal(s.ListenAndServe())

or

rt := new(goku.RouteTable)
rt.Static("staticFile", "/static/(.*)")
rt.Map(
    "blog-page", // route name
    "/blog/p/{page}", // pattern
    map[string]string{"controller": "blog", "action": "page", "page": "0"}, // default
    map[string]string{"page": "\\d+"} // constraint
)
rt.Map(
    "default", // route name
    "/{controller}/{action}", // pattern
    map[string]string{"controller": "home", "action": "index"}, // default
)

Controller And Action

// add a controller named "home"
goku.Controller("home").
    Filters(new(TestControllerFilter)). // this filter is fot controller(all the actions)
    // home controller's index action
    // for http GET
    Get("index", func(ctx *goku.HttpContext) goku.ActionResulter {
    return ctx.Html("Hello World")
}).Filters(new(TestActionFilter)). // this filter is for home.index action
    // home controller's about action
    // for http POST
    Post("about", func(ctx *goku.HttpContext) goku.ActionResulter {
    return ctx.Raw("About")
})
  • get /home/index will return Hello World
  • post /home/index will return 404
  • post /home/about will return About

ActionResult

ActionResulter is type interface. all the action must return ActionResulter. you can return an ActionResulter in the action like this:

// ctx is *goku.HttpContext
ctx.Raw("hi")
ctx.NotFound("oh no! ):")
ctx.Redirect("/")
// or you can return a view that
// will render a template
ctx.View(viewModel)
ctx.Render("viewName", viewModel)

or you can return a ActionResulter by this

return &ActionResult{
    StatusCode: http.StatusNotFound,
    Headers:    map[string]string{"Content-Type": "text/html"},
    Body:       "Page Not Found",
}

for more info, check the code.

View and ViewData

Views are the components that display the application's user interface (UI)

To render a view, you can just return a ViewResut which implement the ActionResulter interface. just like this:

goku.Controller("blog").
    Get("page", func(ctx *goku.HttpContext) goku.ActionResulter {
    blog := GetBlogByid(10)

    // you can add any val to ViewData
    // then you can use it in template
    // like this: {{ .Data.SiteName }}
    ctx.ViewData["SiteName"] = "My Blog"

    // or you can pass a struct to ViewModel
    // then you can use it in template
    // like this: {{ .Model.Title }}
    // that same as blog.Title
    return ctx.View(blog)
})

ctx.View() will find the view in these rules:

  1. /{ViewPath}/{Controller}/{action}
  2. /{ViewPath}/shared/{action}

for example, ServerConfig.ViewPath is set to "views", and return ctx.View() in home controller's about action, it will find the view file in this rule:

  1. {ProjectDir}/views/home/about.html
  2. {ProjectDir}/views/shared/about.html

if you want to return a view that specified view name, you can use ctx.Render:

// it will find the view in these rules:
//      1. /{ViewPath}/{Controller}/{viewName}
//      2. /{ViewPath}/shared/{viewName}
// if viewName start with '/',
// it will find the view direct by viewpath:
//      1. /{ViewPath}/{viewName}
ctx.Render("viewName", ViewModel)

ViewEngine & Template

// you can add any val to ViewData
// then you can use it in template
// like this: {{ .Data.SiteName }}
ctx.ViewData["SiteName"] = "My Blog"

blogs := GetBlogs()
// or you can pass a struct to ViewModel
// then you can use it in template
// like this: {{range .Model}} {{ .Title }} {{end}}
return ctx.View(blogs)

default template engine is golang's template.

<div class="box todos">
    <h2 class="box">{{ .Data.SiteName }}</h2>
    <ul>
      {{range .Model}}
        <li id="blog-{{.Id}}">
          {{.Title}}
        </li>
      {{end}}
    </ul>
</div>

Layout

layout.html

<!DOCTYPE html>
<html>
<head>
    <title>Goku</title>
    {{template "head"}}
</head>
<body>
  {{template "body" .}}
</body>
</html>

body.html

{{define "head"}}
    <!-- add css or js here -->
{{end}}

{{define "body"}}
    I'm main content.
{{end}}

note the dot in {{template "body" .}} , it will pass the ViewData to the sub template.

HtmlHelper?

More Template Engine Support

if you want to use mustache template, check mustache.goku

HttpContext

type HttpContext struct {
    Request        *http.Request       // http request
    responseWriter http.ResponseWriter // http response
    Method         string              // http method

    //self fields
    RouteData *RouteData             // route data
    ViewData  map[string]interface{} // view data for template
    Data      map[string]interface{} // data for httpcontex
    Result    ActionResulter         // action result
    Err       error                  // process error
    User      string                 // user name
    Canceled  bool                   // cancel continue process the request and return
}

Form Validation

you can create a form, to valid the user's input, and get the clean value.

import "github.com/QLeelulu/goku/form"

func CreateCommentForm() *goku.Form {
    name := NewCharField("name", "Name", true).Range(3, 10).Field()
    nickName := NewCharField("nick_name", "Nick Name", false).Min(3).Max(20).Field()
    age := NewIntegerField("age", "Age", true).Range(18, 50).Field()
    content := NewTextField("content", "Content", true).Min(10).Field()

    form := NewForm(name, nickName, age, content)
    return form
}

and then you can use this form like this:

f := CreateCommentForm()
f.FillByRequest(ctx.Request)

if f.Valid() {
    // after valid, we can get the clean values
    m := f.CleanValues()
    // and now you can save m to database
} else {
    // if not valid
    // we can get the valid errors
    errs := f.Errors()
}

checkout form_test.go

DataBase

simple database api.

db, err := OpenMysql("mymysql", "tcp:localhost:3306*test_db/lulu/123456")

// you can use all the api in golang's database/sql
_, err = db.Query("select 1")

// or you can use some simple api provide by goku
r, err := db.Select("test_blog", SqlQueryInfo{
    Fields: "id, title, content",
    Where:  "id>?",
    Params: []interface{}{0},
    Limit:  10,
    Offset: 0,
    Group:  "",
    Order:  "id desc",
})

// insert map
vals := map[string]interface{}{
    "title": "golang",
    "content": "Go is an open source programming environment that " +
        "makes it easy to build simple, reliable, and efficient software.",
    "create_at": time.Now(),
}
r, err := db.Insert("test_blog", vals)

// insert struct
blog := TestBlog{
    Title:    "goku",
    Content:  "a mvc framework",
    CreateAt: time.Now(),
}
r, err = db.InsertStruct(&blog)

// get struct
blog := &TestBlog{}
err = db.GetStruct(blog, "id=?", 3)

// get struct list
qi := SqlQueryInfo{}
var blogs []Blog
err := db.GetStructs(&blogs, qi)

// update by map
vals := map[string]interface{}{
    "title": "js",
}
r, err2 := db.Update("test_blog", vals, "id=?", blog.Id)

// delete
r, err := db.Delete("test_blog", "id=?", 8)

checkout db_test.go

DataBase SQL Debug

if you want to debug what the sql query is, set db.Debug to true

db, err := OpenMysql("mymysql", "tcp:localhost:3306*test_db/username/pwd")
db.Debug = true

after you set db.Debug to true, while you run a db command, it will print the sql query to the log, juse like this:

2012/07/30 20:58:03 SQL: UPDATE `user` SET friends=friends+? WHERE id=?;
                    PARAMS: [[1 2]]

Action Filter

type TestActionFilter struct {
}

func (tf *TestActionFilter) OnActionExecuting(ctx *goku.HttpContext) (ar goku.ActionResulter, err error) {
    ctx.WriteString("OnActionExecuting - TestActionFilter \n")
    return
}
func (tf *TestActionFilter) OnActionExecuted(ctx *goku.HttpContext) (ar goku.ActionResulter, err error) {
    ctx.WriteString("OnActionExecuted - TestActionFilter \n")
    return
}

func (tf *TestActionFilter) OnResultExecuting(ctx *goku.HttpContext) (ar goku.ActionResulter, err error) {
    ctx.WriteString("    OnResultExecuting - TestActionFilter \n")
    return
}

func (tf *TestActionFilter) OnResultExecuted(ctx *goku.HttpContext) (ar goku.ActionResulter, err error) {
    ctx.WriteString("    OnResultExecuted - TestActionFilter \n")
    return
}

Order of the filters execution is:

  1. OnActionExecuting
  2. -> Execute Action -> return ActionResulter
  3. OnActionExecuted
  4. OnResultExecuting
  5. -> ActionResulter.ExecuteResult
  6. OnResultExecuted

Middleware

type TestMiddleware struct {
}

func (tmd *TestMiddleware) OnBeginRequest(ctx *goku.HttpContext) (goku.ActionResulter, error) {
    ctx.WriteString("OnBeginRequest - TestMiddleware \n")
    return nil, nil
}

func (tmd *TestMiddleware) OnBeginMvcHandle(ctx *goku.HttpContext) (goku.ActionResulter, error) {
    ctx.WriteString("  OnBeginMvcHandle - TestMiddleware \n")
    return nil, nil
}
func (tmd *TestMiddleware) OnEndMvcHandle(ctx *goku.HttpContext) (goku.ActionResulter, error) {
    ctx.WriteString("  OnEndMvcHandle - TestMiddleware \n")
    return nil, nil
}

func (tmd *TestMiddleware) OnEndRequest(ctx *goku.HttpContext) (goku.ActionResulter, error) {
    ctx.WriteString("OnEndRequest - TestMiddleware \n")
    return nil, nil
}

Order of the middleware event execution is:

  1. OnBeginRequest
  2. OnBeginMvcHandle(if not the static file request)
  3. => run controller action (if not the static file request)
  4. OnEndMvcHandle(if not the static file request)
  5. OnEndRequest

Log

To use logger in goku, just:

goku.Logger().Logln("i", "am", "log")
goku.Logger().Errorln("oh", "no!", "Server Down!")

this will log like this:

2012/07/14 20:07:46 i am log
2012/07/14 20:07:46 [ERROR] oh no! Server Down!

Authors

License

View the LICENSE file.

You might also like...
A lightweight RESTful web framework for Go
A lightweight RESTful web framework for Go

Goweb A lightweight RESTful web framework for Go. For examples and usage, please read the Goweb API Documentation Read our Articles Who uses Goweb? "U

Mango is a modular web-application framework for Go, inspired by Rack, and PEP333.

Mango Mango is a modular web-application framework for Go, inspired by Rack and PEP333. Note: Not actively maintained. Overview Mango is most of all a

Classy web framework for Go

Martini NOTE: The martini framework is no longer maintained. Martini is a powerful package for quickly writing modular web applications/services in Go

A Go framework for building JSON web services inspired by Dropwizard

Tiger Tonic A Go framework for building JSON web services inspired by Dropwizard. If HTML is your game, this will hurt a little. Like the Go language

Simple web framework for go, still quite beta at this point

WFDR Framework - Beta Release New 18/Feb/2012: Updated for go 1.0, new directory layout to take advantage of the go build tool. Background There's a m

🍐 Elegant Golang REST API Framework
🍐 Elegant Golang REST API Framework

An Elegant Golang Web Framework Goyave is a progressive and accessible web application framework focused on REST APIs, aimed at making backend develop

Golang CTF framework and exploit development module

Golang CTF framework and exploit development module

A simple blog framework built with GO. Uses HTML files and a JSON dict to give you more control over your content.

Go-Blog A simple template based blog framework. Instructions Built for GO version: 1 See the Documentation or Getting Started pages in the wiki. Notes

Goldorak GO is a mini framework for the Go programming language. (unfinished dead code)

Goldorak Go =========== Goldorak GO ! Rétrolaser en action Goldorak GO !! Va accomplir ta mission Dans l'infini Des galaxies Poursuis ta lu

Comments
  • Fix function comments based on best practices from Effective Go

    Fix function comments based on best practices from Effective Go

    Every exported function in a program should have a doc comment. The first sentence should be a summary that starts with the name being declared. From effective go.

    I generated this with CodeLingo and I'm keen to get some feedback, but this is automated so feel free to close it and just say "opt out" to opt out of future CodeLingo outreach PRs.

    opened by Daanikus 2
  • fixed two error when i use todo example.

    fixed two error when i use todo example.

    fixed two error when i use todo example.

    • the mysql datetime format error wher use time.Now() result directly.
    • the id int type error , I fixed but don't kown the reason under the hood.
    opened by dongwq 1
  • Layout template only works under

    Layout template only works under "views/shared"

    I don't know if this is the intended behavior but documentation in the code would have me believe that layouts will be picked up from a top level directory named "layout" by default. This does not work for me. I moved the layout to "views/shared" after looking at the mustache example and it worked.

    opened by pmcoder 1
  • Use CodeLingo to Address Further Issues

    Use CodeLingo to Address Further Issues

    Hi @QLeelulu!

    Thanks for merging the fixes from our earlier pull request. They were generated by CodeLingo which we've used to find a further 699 issues in the repo. This PR adds a set of CodeLingo Tenets which catch any new cases of the found issues in PRs to your repo.

    We're most interested to see if we can help with project specific bugs. Tell us about more interesting issues and we'll see if our tech can help - free of charge.

    Thanks, Angus and the CodeLingo Team

    opened by CodeLingoTeam 0
Flamingo Framework and Core Library. Flamingo is a go based framework for pluggable web projects. It is used to build scalable and maintainable (web)applications.

Flamingo Framework Flamingo is a web framework based on Go. It is designed to build pluggable and maintainable web projects. It is production ready, f

Flamingo 329 Dec 5, 2022
Golanger Web Framework is a lightweight framework for writing web applications in Go.

/* Copyright 2013 Golanger.com. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except

golanger 298 Nov 14, 2022
Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.

Gin Web Framework Gin is a web framework written in Go (Golang). It features a martini-like API with performance that is up to 40 times faster thanks

Gin-Gonic 64.8k Dec 1, 2022
Eudore is the core of a golang lightweight web framework.

Eudore eudore是一个golang轻量级web框架核心,可以轻松扩展成一个技术栈专用框架,具有完整框架设计体系。 反馈和交流请加群组:QQ群373278915。 Features 易扩展:主要设计目标、核心全部解耦,接口即为逻辑。 简单:对象语义明确,框架代码量少复杂度低,无依赖库。 易用

null 73 Nov 7, 2022
Fast and Reliable Golang Web Framework

Gramework The Good Framework Gramework long-term testing stand metrics screenshot made with Gramework Stats Dashboard and metrics middleware What is i

null 372 Dec 1, 2022
The web framework for Golang

uAdmin the Golang Web Framework Easy to use, blazing fast and secure. Originally open source by IntegrityNet Solutions and Services For Documentation:

uADMIN 217 Nov 23, 2022
An ideally refined web framework for Go.

Air An ideally refined web framework for Go. High-performance? Fastest? Almost all web frameworks are using these words to tell people that they are t

Aofei Sheng 420 Nov 23, 2022
Web framework for creating apps using Go in Google AppEngine

Welcome to app.go v3.0 app.go is a simple web framework for use in Google AppEngine. Just copy the app folder to your working folder and import it fro

George Nava 46 Mar 21, 2021
Goal is a toolkit for high productivity web development in Go language in the spirit of Revel Framework that is built around the concept of code generation.

Goal Goal is a set of tools for high productivity web development in Go language. Goal, being mostly inspired by Revel Framework and its discussions,

null 88 Sep 27, 2021
A high level web-framework for Go

go-start is a high level web-framework for Go, like Django for Python or Rails for Ruby. Installation: go get github.com/ungerik/go-start Documentatio

Erik Unger 268 Oct 25, 2022