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

Related tags

Web Frameworks goku
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...
Mvc+go+mysqlのrest API テンプレートリポジトリ

rest-api-temp リポジトリ概要 アドベントカレンダー用に作成 https://qiita.com/advent-calendar/2021/hcb-2021 用途 迅速にrest apiを作らなきゃいけない場合のテンプレート 注意 テンプレートAPIの使用はdocs/api.mdに記載

Goa is a web framework based on middleware, like koa.js.

Goa Goa is under construction, if you are familiar with koa or go and interested in this project, please join us. What is goa? goa = go + koa Just lik

Go-igni: monolith-based web-framework in Go Inspired by classical PHP Frameworks like CodeIgnier & Laravel

go-igni Web Framework in Go About This is research project about developing monolith-based web-framework in Go Inspired by classical PHP Frameworks li

⚡ Rux is an simple and fast web framework. support middleware, compatible http.Handler interface. 简单且快速的 Go web 框架,支持中间件,兼容 http.Handler 接口

Rux Simple and fast web framework for build golang HTTP applications. NOTICE: v1.3.x is not fully compatible with v1.2.x version Fast route match, sup

Faygo is a fast and concise Go Web framework that can be used to develop high-performance web app(especially API) with fewer codes. Just define a struct handler, faygo will automatically bind/verify the request parameters and generate the online API doc. Roche is a Code Generator and Web Framework, makes web development super concise with Go, CleanArch
Roche is a Code Generator and Web Framework, makes web development super concise with Go, CleanArch

It is still under development, so please do not use it. We plan to release v.1.0.0 in the summer. roche is a web framework optimized for microservice

A powerful go web framework for highly scalable and resource efficient web application

webfr A powerful go web framework for highly scalable and resource efficient web application Installation: go get -u github.com/krishpranav/webfr Exa

A powerful go web framework for highly scalable and resource efficient web application

A powerful go web framework for highly scalable and resource efficient web application

A web app built using Go Buffalo web framework

Welcome to Buffalo Thank you for choosing Buffalo for your web development needs. Database Setup It looks like you chose to set up your application us

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
A lightweight MVC framework for Go(Golang)

utron utron is a lightweight MVC framework in Go (Golang) for building fast, scalable and robust database-driven web applications. Features Postgres,

Geofrey Ernest 2.2k Nov 26, 2022
Lightweight web framework based on net/http.

Goweb Light weight web framework based on net/http. Includes routing middleware logging easy CORS (experimental) Goweb aims to rely only on the standa

Travis Harmon 34 Dec 21, 2022
Rocinante is a gin inspired web framework built on top of net/http.

Rocinante Rocinante is a gin inspired web framework built on top of net/http. ⚙️ Installation $ go get -u github.com/fskanokano/rocinante-go ⚡️ Quicks

null 3 Jul 27, 2021
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 343 Jan 5, 2023
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
The jin is a simplified version of the gin web framework that can help you quickly understand the core principles of a web framework.

jin About The jin is a simplified version of the gin web framework that can help you quickly understand the core principles of a web framework. If thi

null 8 Jul 14, 2022
Tigo is an HTTP web framework written in Go (Golang).It features a Tornado-like API with better performance. Tigo是一款用Go语言开发的web应用框架,API特性类似于Tornado并且拥有比Tornado更好的性能。

Tigo(For English Documentation Click Here) 一个使用Go语言开发的web框架。 相关工具及插件 tiger tiger是一个专门为Tigo框架量身定做的脚手架工具,可以使用tiger新建Tigo项目或者执行其他操作。

Karl 1.4k Jan 5, 2023
A gin-like simple golang web framework.

webgo A gin-like simple golang web framework.

vincent 1 Aug 24, 2022
A gin-like simple golang web framework.

A gin-like simple golang web framework.

vincent-言益 1 Aug 24, 2022
基于Golang的框架Gin开发,项目结构和理念参考Laravel。现支持:MySQL、Redis、MVC、拦截器、助手函数、fresh热更、swagger-UI、tpl模版输出、安全的Api。

GinLaravel的构建和运行周期与Beego、Vue、React、Laravel、ThinkPHP、Django等都会有类似的引导思路、参数设置、插件扩展、服务部署、代码统一性、生态护城河等。

方圆 52 Nov 18, 2022