Introducing gobox: A Lightweight Go Framework for HTTP Request Handling
This article introduces gobox, a self‑developed lightweight Go framework that treats each module as a box, explains its HTTP request handling architecture, key components such as System, Router, SimpleRouter, ActionContext, Controller, demonstrates graceful‑restart support with gracehttp, and provides a complete runnable example with sample curl outputs.
Today we introduce gobox , a lightweight Go framework designed so that each independent module is a box ; the collection of boxes forms the gobox package, which can be imported using Go's pkg management mechanism. With Go's dep package manager, each box can be managed as a separate project.
The focus of this edition is the HTTP request handling framework within gobox.
HTTP Request Handling Architecture
Important Objects
System
The System implements Go's http.Handler interface; its ServeHTTP method contains the request processing framework.
Router
Defines and implements the MVC routing lookup process.
type Router interface {
MapRouteItems(cls ...controller.Controller)
DefineRouteItem(pattern string, cl controller.Controller, actionName string)
FindRoute(path string) *Route
}SimpleRouter
A concrete implementation of the Router interface that automatically maps controller and action names based on naming conventions.
Controller name rule: ([A-Z][A-Za-z0-9_]*)Controller$ (lower‑cased to obtain controllerName ).
Action name rule: ([A-Z][A-Za-z0-9_]*)Action$ (lower‑cased and stripped of before / after to obtain actionName ).
Automatic route lookup follows these steps:
Treat request_uri as /controller/action .
If the controller does not exist, default to index (configurable).
If the action does not exist, default to index (configurable).
Custom route lookup can use regular expressions; captured groups become additional string parameters passed to the action.
ActionContext and Controller
ActionContext Interface
type ActionContext interface {
Request() *http.Request
ResponseWriter() http.ResponseWriter
ResponseBody() []byte
SetResponseBody(body []byte)
BeforeAction()
AfterAction()
Destruct()
}Controller Interface
type Controller interface {
NewActionContext(req *http.Request, respWriter http.ResponseWriter) ActionContext
}BaseActionContext Struct
type BaseActionContext struct {
Req *http.Request
RespWriter http.ResponseWriter
RespBody []byte
}
func (this *BaseActionContext) Request() *http.Request { return this.Req }
func (this *BaseActionContext) ResponseWriter() http.ResponseWriter { return this.RespWriter }
func (this *BaseActionContext) ResponseBody() []byte { return this.RespBody }
func (this *BaseActionContext) SetResponseBody(body []byte) { this.RespBody = body }
func (this *BaseActionContext) BeforeAction() { this.RespBody = append(this.RespBody, []byte(" index before ")...) }
func (this *BaseActionContext) AfterAction() { this.RespBody = append(this.RespBody, []byte(" index after ")...) }
func (this *BaseActionContext) Destruct() { println(" index destruct ") }DemoActionContext (inherits BaseActionContext)
type DemoActionContext struct { *BaseActionContext }
func (this *DemoActionContext) BeforeAction() { this.RespBody = append(this.RespBody, []byte(" demo before ")...) }
func (this *DemoActionContext) AfterAction() { this.RespBody = append(this.RespBody, []byte(" demo after ")...) }
func (this *DemoActionContext) Destruct() { println(" demo destruct ") }Graceful Restart Server (gracehttp)
Provides an HTTP server that supports zero‑downtime restarts.
gracehttp.ListenAndServe(":8001", sys)Complete Example
The following Go program demonstrates how to wire the components together, define routes, and start the server.
package main
import (
"github.com/goinbox/gohttp/controller"
"github.com/goinbox/gohttp/gracehttp"
"github.com/goinbox/gohttp/router"
"github.com/goinbox/gohttp/system"
"net/http"
)
func main() {
dcl := new(DemoController)
r := router.NewSimpleRouter()
r.DefineRouteItem("^/g/([0-9]+)$", dcl, "get")
r.MapRouteItems(new(IndexController), dcl)
sys := system.NewSystem(r)
gracehttp.ListenAndServe(":8001", sys)
}
type DemoActionContext struct { *BaseActionContext }
func (this *DemoActionContext) BeforeAction() { this.RespBody = append(this.RespBody, []byte(" demo before ")...) }
func (this *DemoActionContext) AfterAction() { this.RespBody = append(this.RespBody, []byte(" demo after ")...) }
func (this *DemoActionContext) Destruct() { println(" demo destruct ") }
type DemoController struct {}
func (this *DemoController) NewActionContext(req *http.Request, respWriter http.ResponseWriter) ActionContext {
return &DemoActionContext{&BaseActionContext{Req: req, RespWriter: respWriter}}
}
func (this *DemoController) DemoAction(context *DemoActionContext) {
context.RespBody = append(context.RespBody, []byte(" demo action ")...)
}
type IndexController struct {}
func (this *IndexController) NewActionContext(req *http.Request, respWriter http.ResponseWriter) ActionContext {
return &BaseActionContext{Req: req, RespWriter: respWriter}
}
func (this *IndexController) IndexAction(context *BaseActionContext) {
context.RespBody = append(context.RespBody, []byte(" index action ")...)
}
func (this *IndexController) RedirectAction(context *BaseActionContext) {
system.Redirect302("https://github.com/goinbox")
}
func (this *IndexController) GetAction(context *BaseActionContext, id string) {
context.RespBody = append(context.RespBody, []byte(" get action id = "+id)...)
}Sample Curl Requests and Outputs
curl http://127.0.0.1:8001/
# Output: index before index action index after
curl http://127.0.0.1:8001/index/redirect -I
# HTTP/1.1 302 Found
# Content-Type: text/html; charset=utf-8
# Location: https://github.com/goinbox
curl http://127.0.0.1:8001/demo/demo
# Output: demo before demo action demo after
curl http://127.0.0.1:8001/g/123
# Output: demo before get action id = 123 demo afterAll Destruct calls print their respective messages, e.g., index destruct and demo destruct .
Feel free to try gobox, and report any issues for a quick response. Thank you!
360 Tech Engineering
Official tech channel of 360, building the most professional technology aggregation platform for the brand.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.