ThinkGo is a lightweight MVC framework written in Go (Golang).
Installation
The only requirement is the Go Programming Language
go get -u github.com/forgoer/thinkgo
Quick start
package main
import (
"fmt"
"github.com/forgoer/thinkgo"
"github.com/forgoer/thinkgo/think"
)
func main() {
th := thinkgo.New()
th.RegisterRoute(func(route *think.Route) {
route.Get("/", func(req *think.Req) *think.Res {
return think.Text("Hello ThinkGo !")
})
route.Get("/ping", func(req *think.Req) *think.Res {
return think.Json(map[string]string{
"message": "pong",
})
})
// Dependency injection
route.Get("/user/{name}", func(req *think.Req, name string) *think.Res {
return think.Text(fmt.Sprintf("Hello %s !", name))
})
})
// listen and serve on 0.0.0.0:9011
th.Run()
}
Features
Routing
Basic Routing
The most basic routes accept a URI and a Closure, providing a very simple and expressive method of defining routes:
think.RegisterRoute(func(route *router.Route) {
route.Get("/foo", func(req *context.Request) *context.Response {
return thinkgo.Text("Hello ThinkGo !")
})
})
Available Router Methods
The router allows you to register routes that respond to any HTTP verb:
route.Get("/someGet", getting)
route.Post("/somePost", posting)
route.Put("/somePut", putting)
route.Delete("/someDelete", deleting)
route.Patch("/somePatch", patching)
route.Options("/someOptions", options)
Any
route.Any("/someAny", any)
Parameters in path
Of course, sometimes you will need to capture segments of the URI within your route. For example, you may need to capture a user's ID from the URL. You may do so by defining route parameters:
route.Get("/user/{id}", func(req *context.Request, id string) *context.Response {
return thinkgo.Text(fmt.Sprintf("User %s", id))
})
You may define as many route parameters as required by your route:
route.Get("/posts/{post}/comments/{comment}", func(req *context.Request, postId, commentId string) *context.Response {
//
})
Route Prefixes
admin
route.Prefix("/admin").Group(func(group *router.Route) {
group.Prefix("user").Group(func(group *router.Route) {
// ...
})
group.Prefix("posts").Group(func(group *router.Route) {
// ...
})
})
Route Groups
Route groups allow you to share route attributes, such as middleware or prefix, across a large number of routes without needing to define those attributes on each individual route.
route.Prefix("/admin").Group(func(group *router.Route) {
group.Prefix("user").Group(func(group *router.Route) {
group.Get("", func(request *context.Request) *context.Response {
return thinkgo.Text("admin user !")
}).Middleware(func(request *context.Request, next router.Closure) interface{} {
if _, err := request.Input("id"); err != nil {
return thinkgo.Text("Invalid parameters")
}
return next(request)
})
group.Get("edit", func(request *context.Request) *context.Response {
return thinkgo.Text("admin user edit !")
})
}).Middleware(func(request *context.Request, next router.Closure) interface{} {
if _, err := request.Input("user"); err != nil {
return thinkgo.Text("Invalid parameters")
}
return next(request)
})
}).Middleware(func(request *context.Request, next router.Closure) interface{} {
if _, err := request.Input("token"); err != nil {
return thinkgo.Text("Invalid parameters")
}
return next(request)
})
Middleware
Middleware
route.Get("/foo", func(request *context.Request) *context.Response {
return thinkgo.Text("Hello ThinkGo !")
}).Middleware(func(request *context.Request, next router.Closure) interface{} {
if _, err := request.Input("name"); err != nil {
return thinkgo.Text("Invalid parameters")
}
return next(request)
})
Before Middleware
before
func(request *context.Request, next router.Closure) interface{} {
// Perform action
// ...
return next(request)
}
After Middleware
after
func(request *context.Request, next router.Closure) interface{} {
response := next(request)
// Perform action
// ...
return response
}
Controller
Basic Controller
Below is an example of a basic controller class.
package controller
import (
"github.com/forgoer/thinkgo"
"github.com/forgoer/thinkgo/context"
)
func Index(req *context.Request) *context.Response {
return thinkgo.Text("Hello ThinkGo !")
}
You can define a route to this controller like so:
route.Get("/", controller.Index)
Resource Controller
This feature will be supported in a future release.
HTTP Request
Accessing The Request
To obtain an instance of the current HTTP request via dependency injection
func Handler(req *context.Request) *context.Response {
name := req.Input("name")
}
Dependency Injection & Route Parameters
name
route.Put("/user/{name}", func(req *context.Request, name string) *context.Response {
//
})
Request Path & Method
pathhttp://domain.com/foo/barpathfoo/bar
uri := req.GetPath()
method
method := req.GetMethod();
Retrieving Cookies From Requests
name, _ := request.Cookie("name")
HTTP Response
*context.Response
Creating Responses
a simple strings or json Response:
thinkgo.Text("Hello ThinkGo !")
thinkgo.Json(map[string]string{
"message": "pong",
})
Attaching Cookies To Responses
response.Cookie("name", "alice")
Redirects
route.Get("/redirect", func(request *context.Request) *context.Response {
return context.Redirect("https://www.google.com")
})
View
views
view.ParseGlob("/path/to/views/*")
views
views/layout.html
{{ define "layout" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ .Title }}</title>
</head>
<body>
{{ template "content" .}}
</body>
</html>
{{ end }}
views/tpl.html
{{ define "content" }}
<h2>{{ .Message }}</h2>
{{ end }}
{{ template "layout" . }}
Render
route.Get("/tpl", func(request *context.Request) *context.Response {
data := map[string]interface{}{"Title": "ThinkGo", "Message": "Hello ThinkGo !"}
return view.Render("tpl.html", data)
})
HTTP Session
When the app starts, you need to register the session handler.
think.RegisterHandler(app.NewSessionHandler)
ThinkGo
- cookie - sessions are stored in cookies
- file - sessions are stored in files.
Using The Session
retrieving Data like this:
request.Session().Get("user")
storing Data like this:
request.Session().Set("user", "alice")
Adding Custom Session Drivers
Handler
type Handler interface {
Read(id string) string
Write(id string, data string)
}
Once your driver has been implemented, you are ready to register it:
import "github.com/forgoer/thinkgo/session"
session.Extend("my_session", MySessionHandler)
Logging
The logger provides the eight logging levels defined in RFC 5424: emergency, alert, critical, error, warning, notice, info and debug.
Basic Usage
import "github.com/forgoer/thinkgo/log"
log.Debug("log with Debug")
log.Info("log with Info")
log.Notice("log with Notice")
log.Warn("log with Warn")
log.Error("log with Error")
log.Crit("log with Crit")
log.Alert("log with Alert")
log.Emerg("log with Emerg")
Log Storage
dailyconsole
daily
import (
"github.com/forgoer/thinkgo/log"
"github.com/forgoer/thinkgo/log/handler"
"github.com/forgoer/thinkgo/log/record"
)
fh := handler.NewFileHandler("path/to/thinkgo.log", record.INFO)
log.GetLogger().PushHandler(fh)
Cache
ThinkGo Cache Currently supports redis, memory, and can customize the store adapter.
Basic Usage
import (
"github.com/forgoer/thinkgo/cache"
"time"
)
var foo string
// Create a cache with memory store
c, _ := cache.Cache(cache.NewMemoryStore("thinkgo"))
// Set the value
c.Put("foo", "thinkgo", 10 * time.Minute)
// Get the string associated with the key "foo" from the cache
c.Get("foo", &foo)
Retrieve & Store
Remember
var foo int
cache.Remember("foo", &a, 1*time.Minute, func() interface{} {
return "thinkgo"
})
ORM
refer to ThinkORM
License
This project is licensed under the Apache 2.0 license.
Contact
If you have any issues or feature requests, please contact us. PR is welcomed.