Skip to content
/ rux Public

⚡ Rux is an simple and fast web framework. support route group, param route binding, middleware, compatible http.Handler interface. 简单且快速的 Go api/web 框架,支持路由分组,路由参数绑定,中间件,兼容 http.Handler 接口

License

Notifications You must be signed in to change notification settings

gookit/rux

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rux

GitHub go.mod Go version Actions Status GitHub tag (latest SemVer) GoDoc Coverage Status Go Report Card

Simple and fast web framework for build golang HTTP applications.

  • Fast route match, support route group
  • Support route path params and named routing
  • Support cache recently accessed dynamic routes
  • Support route middleware, group middleware, global middleware
  • Support quickly add a RESETFul or Controller style structs
  • Support generic http.Handler interface middleware
  • Support static file access handle
  • Support add handlers for handle NotFound and NotAllowed

中文说明请看 README.zh-CN

GoDoc

Install

go get github.com/gookit/rux

Quick start

package main

import (
	"github.com/gookit/rux"
)

func main() {
	r := rux.New()
	
	// Add Routes:
	r.GET("/", func(c *rux.Context) {
		c.Text(200, "hello")
	})
	r.GET("/hello/{name}", func(c *rux.Context) {
		c.Text(200, "hello " + c.Param("name"))
	})
	r.POST("/post", func(c *rux.Context) {
		c.Text(200, "hello")
	})
	// add multi method support for an route path
	r.Add("/post[/{id}]", func(c *rux.Context) {
		if c.Param("id") == "" {
			// do create post
			c.Text(200, "created")
			return
		}

		id := c.Params.Int("id")
		// do update post
		c.Text(200, "updated " + fmt.Sprint(id))
	}, rux.POST, rux.PUT)

	// Start server
	r.Listen(":8080")
	// can also
	// http.ListenAndServe(":8080", r)
}

Route Group

r.Group("/articles", func() {
    r.GET("", func(c *rux.Context) {
        c.Text(200, "view list")
    })
    r.POST("", func(c *rux.Context) {
        c.Text(200, "create ok")
    })
    r.GET(`/{id:\d+}`, func(c *rux.Context) {
        c.Text(200, "view detail, id: " + c.Param("id"))
    })
})

Path Params

You can add the path params like: {id} Or {id:\d+}

// can access by: "/blog/123"
r.GET(`/blog/{id:\d+}`, func(c *rux.Context) {
    c.Text(200, "view detail, id: " + c.Param("id"))
})

optional params, like /about[.html] or /posts[/{id}]:

// can access by: "/blog/my-article" "/blog/my-article.html"
r.GET(`/blog/{title:\w+}[.html]`, func(c *rux.Context) {
    c.Text(200, "view detail, id: " + c.Param("id"))
})

r.Add("/posts[/{id}]", func(c *rux.Context) {
    if c.Param("id") == "" {
        // do create post
        c.Text(200, "created")
        return
    }

    id := c.Params.Int("id")
    // do update post
    c.Text(200, "updated " + fmt.Sprint(id))
}, rux.POST, rux.PUT)

Use Middleware

rux support use middleware, allow:

  • global middleware
  • group middleware
  • route middleware

Call priority: global middleware -> group middleware -> route middleware

Examples:

package main

import (
	"fmt"

	"github.com/gookit/rux"
)

func main() {
	r := rux.New()
	
	// add global middleware
	r.Use(func(c *rux.Context) {
	    // do something ...
	})
	
	// add middleware for the route
	route := r.GET("/middle", func(c *rux.Context) { // main handler
		c.WriteString("-O-")
	}, func(c *rux.Context) { // middle 1
        c.WriteString("a")
        c.Next() // Notice: call Next()
        c.WriteString("A")
        // if call Abort(), will abort at the end of this middleware run
        // c.Abort() 
    })
	
	// add more by Use()
	route.Use(func(c *rux.Context) { // middle 2
		c.WriteString("b")
		c.Next()
		c.WriteString("B")
	})

	// now, access the URI /middle
	// will output: ab-O-BA
}
  • Call sequence: middle 1 -> middle 2 -> main handler -> middle 2 -> middle 1
  • Flow chart:
        +-----------------------------+
        | middle 1                    |
        |  +----------------------+   |
        |  | middle 2             |   |
 start  |  |  +----------------+  |   | end
------->|  |  |  main handler  |  |   |--->----
        |  |  |________________|  |   |    
        |  |______________________|   |  
        |_____________________________|

more please see middleware_test.go middleware tests

Use http.Handler

rux is support generic http.Handler interface middleware

You can use rux.WrapHTTPHandler() convert http.Handler as rux.HandlerFunc

package main

import (
	"net/http"
	
	"github.com/gookit/rux"
	// here we use gorilla/handlers, it provides some generic handlers.
	"github.com/gorilla/handlers"
)

func main() {
	r := rux.New()
	
	// create a simple generic http.Handler
	h0 := http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
		w.Header().Set("new-key", "val")
	})
	
	r.Use(rux.WrapHTTPHandler(h0), rux.WrapHTTPHandler(handlers.ProxyHeaders()))
	
	r.GET("/", func(c *rux.Context) {
		c.Text(200, "hello")
	})
	// add routes ...
	
    // Wrap our server with our gzip handler to gzip compress all responses.
    http.ListenAndServe(":8000", handlers.CompressHandler(r))
}

More Usage

Static Assets

package main

import (
	"embed"	
	"net/http"

	"github.com/gookit/rux"
)

//go:embed static
var embAssets embed.FS

func main() {
	r := rux.New()

	// one file
	r.StaticFile("/site.js", "testdata/site.js")

	// allow any files in the directory.
	r.StaticDir("/static", "testdata")

	// file type limit in the directory
	r.StaticFiles("/assets", "testdata", "css|js")

	// go 1.16+: use embed assets. access: /embed/static/some.html
	r.StaticFS("/embed", http.FS(embAssets))
}

Name Route

In rux, you can add a named route, and you can get the corresponding route instance(rux.Route) from the router according to the name.

Examples:

	r := rux.New()
	
	// Method 1
	myRoute := rux.NewNamedRoute("name1", "/path4/some/{id}", emptyHandler, "GET")
	r.AddRoute(myRoute)

	// Method 2
	rux.AddNamed("name2", "/", func(c *rux.Context) {
		c.Text(200, "hello")
	})

	// Method 3
	r.GET("/hi", func(c *rux.Context) {
		c.Text(200, "hello")
	}).NamedTo("name3", r)
	
	// get route by name
	myRoute = r.GetRoute("name1")

Redirect

redirect to other page

r.GET("/", func(c *rux.Context) {
    c.AbortThen().Redirect("/login", 302)
})

// Or
r.GET("/", func(c *rux.Context) {
    c.Redirect("/login", 302)
    c.Abort()
})

r.GET("/", func(c *rux.Context) {
    c.Back()
    c.Abort()
})

Cookies

you can quick operate cookies by FastSetCookie() DelCookie()

Note: You must set or delete cookies before writing BODY content

r.GET("/setcookie", func(c *rux.Context) {
    c.FastSetCookie("rux_cookie2", "test-value2", 3600)
    c.SetCookie("rux_cookie", "test-value1", 3600, "/", c.Req.URL.Host, false, true)
	c.WriteString("hello, in " + c.URL().Path)
})

r.GET("/delcookie", func(c *rux.Context) {
	val := ctx.Cookie("rux_cookie") // "test-value1"
	c.DelCookie("rux_cookie", "rux_cookie2")
})

Multi Domains

code is refer from julienschmidt/httprouter

package main

import (
	"log"
	"net/http"

	"github.com/gookit/rux"
)

type HostSwitch map[string]http.Handler

// Implement the ServeHTTP method on our new type
func (hs HostSwitch) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Check if a http.Handler is registered for the given host.
	// If yes, use it to handle the request.
	if router := hs[r.Host]; router != nil {
		router.ServeHTTP(w, r)
	} else {
		// Handle host names for which no handler is registered
		http.Error(w, "Forbidden", 403) // Or Redirect?
	}
}

func main() {
	// Initialize a router as usual
	router := rux.New()
	router.GET("/", Index)
	router.GET("/hello/{name}", func(c *rux.Context) {})

	// Make a new HostSwitch and insert the router (our http handler)
	// for example.com and port 12345
	hs := make(HostSwitch)
	hs["example.com:12345"] = router

	// Use the HostSwitch to listen and serve on port 12345
	log.Fatal(http.ListenAndServe(":12345", hs))
}

RESETFul Style

package main

import (
	"log"
	"net/http"

	"github.com/gookit/rux"
)

type Product struct {
}

// Uses middlewares [optional]
func (Product) Uses() map[string][]rux.HandlerFunc {
	return map[string][]rux.HandlerFunc{
		// function name: handlers
		"Delete": []rux.HandlerFunc{
			handlers.HTTPBasicAuth(map[string]string{"test": "123"}),
			handlers.GenRequestID(),
		},
	}
}

// all products [optional]
func (p *Product) Index(c *rux.Context) {
	// do something
}

// create product [optional]
func (p *Product) Create(c *rux.Context) {
	// do something
}

// save new product [optional]
func (p *Product) Store(c *rux.Context) {
	// do something
}

// show product with {id} [optional]
func (p *Product) Show(c *rux.Context) {
	// do something
}

// edit product [optional]
func (p *Product) Edit(c *rux.Context) {
	// do something
}

// save edited product [optional]
func (p *Product) Update(c *rux.Context) {
	// do something
}

// delete product [optional]
func (p *Product) Delete(c *rux.Context) {
	// do something
}

func main() {
	router := rux.New()

	// methods	Path	Action	Route Name
    // GET	/product	index	product_index
    // GET	/product/create	create	product_create
    // POST	/product	store	product_store
    // GET	/product/{id}	show	product_show
    // GET	/product/{id}/edit	edit	product_edit
    // PUT/PATCH	/product/{id}	update	product_update
    // DELETE	/product/{id}	delete	product_delete
    // resetful style
	router.Resource("/", new(Product))

	log.Fatal(http.ListenAndServe(":12345", router))
}

Controller Style

package main

import (
	"log"
	"net/http"

	"github.com/gookit/rux"
)

// News controller
type News struct {
}

func (n *News) AddRoutes(g *rux.Router) {
	g.GET("/", n.Index)
	g.POST("/", n.Create)
	g.PUT("/", n.Edit)
}

func (n *News) Index(c *rux.Context) {
	// Do something
}

func (n *News) Create(c *rux.Context) {
	// Do something
}

func (n *News) Edit(c *rux.Context) {
	// Do something
}

func main() {
	router := rux.New()

	// controller style
	router.Controller("/news", new(News))

	log.Fatal(http.ListenAndServe(":12345", router))
}

Build URL

package main

import (
	"log"
	"net/http"

	"github.com/gookit/rux"
)

func main() {
	// Initialize a router as usual
	router := rux.New()
	router.GET(`/news/{category_id}/{new_id:\d+}/detail`, func(c *rux.Context) {
		var u = make(url.Values)
        u.Add("username", "admin")
        u.Add("password", "12345")
		
		b := rux.NewBuildRequestURL()
        // b.Scheme("https")
        // b.Host("www.mytest.com")
        b.Queries(u)
        b.Params(rux.M{"{category_id}": "100", "{new_id}": "20"})
		// b.Path("/dev")
        // println(b.Build().String())
        
        println(c.Router().BuildRequestURL("new_detail", b).String())
		// result:  /news/100/20/detail?username=admin&password=12345
		// get current route name
		if c.MustGet(rux.CTXCurrentRouteName) == "new_detail" {
            // post data etc....
        }
	}).NamedTo("new_detail", router)

	// Use the HostSwitch to listen and serve on port 12345
	log.Fatal(http.ListenAndServe(":12345", router))
}

Help

  • lint
golint ./...
  • format check
# list error files
gofmt -s -l ./
# fix format and write to file
gofmt -s -w some.go
  • unit test
go test -cover ./...

Gookit Packages

See also

License

MIT

About

⚡ Rux is an simple and fast web framework. support route group, param route binding, middleware, compatible http.Handler interface. 简单且快速的 Go api/web 框架,支持路由分组,路由参数绑定,中间件,兼容 http.Handler 接口

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •