非常轻量级的和简单的Go Web框架

网友投稿 648 2022-10-27

非常轻量级的和简单的Go Web框架

非常轻量级的和简单的Go Web框架

WebGo v4.1.1

WebGo is a minimalistic framework for Go to build web applications (server side) with zero 3rd party dependencies. Unlike full-fledged frameworks, it gets out of your way as soon as possible in the execution flow. WebGo has always been and will always be Go standard library compliant; with the HTTP handlers having the same signature as http.HandlerFunc.

Important ❗

Regression introduced in v4.0.4, exists on v4.0.6 as well. Requests panic when not using Webgo's response methods (e.g. R200, Send, SendResponse etc.) because the default HTTP status is set as 0 ContextPayload.URIParams(*http.Request)map[string]string was replaced despite being newly introduced in v3.5.4. The new function is ContextPayload.Params()map[string]string, and has a slight performance advantage compared to URIParams

Index

RouterHandler chainingMiddlewareHelper functionsHTTPS readyGraceful shutdownLoggingUsage

Router

The router is one of the most important component of a web application. It helps identify the HTTP requests and pass them on to respective handlers. A handler is identified using a URI. WebGo supports defining URIs with the following patterns

/api/usersStatic URI pattern with no variables /api/users/:userIDURI pattern with variable userID (named URI parameter)This will not match /api/users/johndoe/account. It only matches till /api/users/johndoe/If TrailingSlash is set to true, refer to sample /api/users/:misc*Named URI variable miscThis matches everything after /api/users. e.g. /api/users/a/b/c/d

If multiple patterns match the same URI, the first matching handler would be executed. Refer to the sample to see how routes are configured. A WebGo Route is defined as following:

webgo.Route{ // A name for the API (preferrably unique) Name string // HTTP verb, i.e. GET, POST, PUT, PATCH, HEAD, DELETE Method string // The URI pattern Pattern string // If the URI ends with a '/', should it be considered valid or not? e.g. '/api/users' vs '/api/users/' TrailingSlash bool // In case of chained handlers, should the execution continue after one of the handlers have // responded to the HTTP request FallThroughPostResponse bool // The list of HTTP handlers Handlers []http.HandlerFunc}

You can access named parameters of the URI using the Context function.

func helloWorld(w http.ResponseWriter, r *http.Request) { // WebGo context wctx := webgo.Context(r) // URI paramaters, map[string]string params := wctx.Params() // route, the webgo.Route which is executing this request route := wctx.Route webgo.R200( w, fmt.Sprintf( "Route name: '%s', params: '%s'", route.Name, params, ), )}

Handler chaining

Handler chaining lets you execute multiple handlers for a given route. Execution of a chain can be configured to run even after a handler has written a response to the http request. This is made possible by setting FallThroughPostResponse to true (refer sample).

webgo.Route{ Name: "chained", Method: http.MethodGet, Pattern: "/api", TrailingSlash: false, FallThroughPostResponse: true, Handlers []http.HandlerFunc{ handler1, handler2, . . . }}

Middleware

WebGo middleware lets you wrap all the routes with a middleware. Unlike handler chaining, middleware applies to all the handlers. All middleware should be of type Middlware. The router exposes a method Use && UseOnSpecialHandlers to add a Middleware to the router. Following code shows how a middleware can be used in WebGo.

import ( "github.com/bnkamalesh/webgo/v4" "github.com/bnkamalesh/webgo/v4/middleware")func routes() []*webgo.Route { return []*webgo.Route{ &webo.Route{ Name: "home", Method: http.http.MethodGet, Pattern: "/", Handlers: []http.HandlerFunc{ func(w http.ResponseWriter, r *http.Request) { webgo.R200(w, "home") } }, }, }}func main() { router := webgo.NewRouter(*webgo.Config{ Host: "", Port: "8080", ReadTimeout: 15 * time.Second, WriteTimeout: 60 * time.Second, }, routes()) router.UseOnSpecialHandlers(middleware.AccessLog) router.Use(middleware.AccessLog) router.Start()}

Any number of middleware can be added to the router, the order of execution of middleware would be LIFO (Last In First Out). i.e. in case of the following code

func main() { router.Use(middleware.AccessLog) router.Use(middleware.CorsWrap())}

CorsWrap would be executed first, followed by AccessLog.

Helper functions

WebGo provides a few helper functions.

ResponseStatus(w http.ResponseWriter) get the HTTP status code from response writerSendHeader(w http.ResponseWriter, rCode int) - Send only an HTTP response header with the provided response code.Send(w http.ResponseWriter, contentType string, data interface{}, rCode int) - Send any response as is, with the provided content type and response codeSendResponse(w http.ResponseWriter, data interface{}, rCode int) - Send a JSON response wrapped in WebGo's default response struct.SendError(w http.ResponseWriter, data interface{}, rCode int) - Send a JSON response wrapped in WebGo's default error response structRender(w http.ResponseWriter, data interface{}, rCode int, tpl *template.Template) - Render renders a Go template, with the provided data & response code.

Few more helper functions are available, you can check them here.

When using Send or SendResponse, the response is wrapped in WebGo's response struct and is serialized as JSON.

{ "data": "", "status": ""}

When using SendError, the response is wrapped in WebGo's error response struct and is serialzied as JSON.

{ "errors": "", "status": ""}

HTTPS ready

HTTPS server can be started easily, by providing the key & cert file. You can also have both HTTP & HTTPS servers running side by side.

Start HTTPS server

cfg := &webgo.Config{ Port: "80", HTTPSPort: "443", CertFile: "/path/to/certfile", KeyFile: "/path/to/keyfile",}router := webgo.NewRouter(cfg, routes())router.StartHTTPS()

Starting both HTTP & HTTPS server

cfg := &webgo.Config{ Port: "80", HTTPSPort: "443", CertFile: "/path/to/certfile", KeyFile: "/path/to/keyfile",}router := webgo.NewRouter(cfg, routes())go router.StartHTTPS()router.Start()

Graceful shutdown

Graceful shutdown lets you shutdown the server without affecting any live connections/clients connected to the server. It will complete executing all the active/live requests before shutting down.

Sample code to show how to use shutdown

func main() { osSig := make(chan os.Signal, 5) cfg := &webgo.Config{ Host: "", Port: "8080", ReadTimeout: 15 * time.Second, WriteTimeout: 60 * time.Second, ShutdownTimeout: 15 * time.Second, } router := webgo.NewRouter(cfg, routes()) go func() { <-osSig // Initiate HTTP server shutdown err := router.Shutdown() if err != nil { fmt.Println(err) os.Exit(1) } else { fmt.Println("shutdown complete") os.Exit(0) } // If you have HTTPS server running, you can use the following code // err := router.ShutdownHTTPS() // if err != nil { // fmt.Println(err) // os.Exit(1) // } else { // fmt.Println("shutdown complete") // os.Exit(0) // } }() signal.Notify(osSig, os.Interrupt, syscall.SIGTERM) router.Start() for { // Prevent main thread from exiting, and wait for shutdown to complete time.Sleep(time.Second * 1) }}

Logging

WebGo exposes a singleton & global scoped logger variable LOGHANDLER with which you can plugin your custom logger. Any custom logger should implement WebGo's Logger interface.

type Logger interface { Debug(data ...interface{}) Info(data ...interface{}) Warn(data ...interface{}) Error(data ...interface{}) Fatal(data ...interface{})}

Configuring the default Logger

The default logger uses Go standard library's log.Logger with os.Stdout (for debug and info logs) & os.Stderr (for warning, error, fatal) as default io.Writers. You can set the io.Writer as well as disable specific types of logs using the GlobalLoggerConfig(stdout, stderr, cfgs...) function.

GlobalLoggerConfig(nil, nil, LogCfgDisableDebug, LogCfgDisableInfo...)

Usage is shown in cmd/main.go.

Usage

A fully functional sample is provided here. You can try the following API calls with the sample app.

http://localhost:8080/Route with no named parameters configured http://localhost:8080/matchall/Route with wildcard parameter configuredAll URIs which begin with /matchall will be matched because it has a wildcard variablee.g. http://localhost:8080/matchall/hellohttp://localhost:8080/matchall/hello/worldhttp://localhost:8080/matchall/hello/world/user `http://localhost:8080/api/Route with a named 'param' configuredIt will match all requests which match /api/e.g. http://localhost:8080/api/hellohttp://localhost:8080/api/world

How to run the sample

If you have Go installed on your system, open your terminal and:

$ cd $GOPATH/src$ mkdir -p github.com/bnkamalesh$ cd github.com/bnkamalesh$ git clone https://github.com/bnkamalesh/webgo.git$ cd webgo$ go run cmd/main.goInfo 2020/06/03 12:55:26 HTTP server, listening on :8080

Or if you have docker, open your terminal and:

$ git clone https://github.com/bnkamalesh/webgo.git$ cd webgo$ docker run \-p 8080:8080 \-v ${PWD}:/go/src/github.com/bnkamalesh/webgo/ \-w /go/src/github.com/bnkamalesh/webgo/cmd \--rm -ti golang:latest go run main.goInfo 2020/06/03 12:55:26 HTTP server, listening on :8080

Contributing

Refer here to find out details about making a contribution

Credits

Thanks to all the contributors

The gopher

The gopher used here was created using Gopherize.me. WebGo stays out of developers' way, so sitback and enjoy a cup of coffee like this gopher.

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Spring Data Jpa框架最佳实践示例
下一篇:Baa 一个简单高效的Go web开发框架
相关文章

 发表评论

暂时没有评论,来抢沙发吧~