Coder Social home page Coder Social logo

gookit / rux Goto Github PK

View Code? Open in Web Editor NEW
98.0 5.0 16.0 823 KB

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

Home Page: https://pkg.go.dev/github.com/gookit/rux?tab=doc

License: MIT License

Go 95.08% Dockerfile 1.26% Makefile 3.47% HTML 0.19%
router http-router go mux http-server http-middleware http-handler middleware

rux's Introduction

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

NOTICE: v1.3.x is not fully compatible with v1.2.x version

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

  • gookit/ini Go config management, use INI files
  • gookit/rux Simple and fast request router for golang HTTP
  • gookit/gcli build CLI application, tool library, running CLI commands
  • gookit/slog Concise and extensible go log library
  • gookit/event Lightweight event manager and dispatcher implements by Go
  • gookit/cache Generic cache use and cache manager for golang. support File, Memory, Redis, Memcached.
  • gookit/config Go config management. support JSON, YAML, TOML, INI, HCL, ENV and Flags
  • gookit/color A command-line color library with true color support, universal API methods and Windows support
  • gookit/filter Provide filtering, sanitizing, and conversion of golang data
  • gookit/validate Use for data validation and filtering. support Map, Struct, Form data
  • gookit/goutil Some utils for the Go: string, array/slice, map, format, cli, env, filesystem, test and more
  • More please see https://github.com/gookit

See also

License

MIT

rux's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar dulumao avatar inhere avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

rux's Issues

StaticFS embed的路径问题

之前提的一个无法embed的问题,测试了下确实可以。但现在遇到一个embed的路径问题。
假设html的目录是static,目录下有index.html和main.js文件

//go:embed static
var embAssets embed.FS

r.StaticFS("/", http.FS(embAssets))

浏览器访问时需要输入:http://127.0.0.1:8080/static/index.html 但index.html中一般引入js的路径是http://127.0.0.1:8080/main.js 导致无法访问。所以希望在StaticFS中,能够把"static"这一层目录处理掉

feat: HTTP cache implementation.

An HTTP cache system would be great in rux to avoid the execution of unchanged response.

I can implement Souin as the HTTP cache middleware. With that it will support the CDN validation/invalidation too, set default cache-control header, store in a distributed system using olric or in memory with badger.

It's already available as Træfik/Tyk plugin, skipper/gin/echo middleware, and is used in the official caddy cache-handler.

Cheers ✌️

可否考虑引入fasthttp?

大佬您好,我非常喜欢您写的那些工具。我最近看了很多原声net与fasthttp的性能对比的测试结论。想问下这个框架要不要考虑使用呢?感觉fasthttp比较好用的框架还是少...

Sent from PPHub

Save middleware auth data to *rux.Context

I want to save some data to Context from middleware like below
Middleware.go
func CheckAuth(c *rux.Context) { c.SaveDataForMainController(map[string]string{ "name": "xxxxxxxx", }) c.Next() }

In main controller i want to access data like this
Controller.go
func profile(c *rux.Context) { data := c.getSavedData() }

Is there any way to do like this or can you add features like this

url with trainling slash /blog/100/ match r.GET(`/blog/{id:\d+}`,

System (please complete the following information):

  • OS: win64
  • GO Version: 1.16
  • Pkg Version: 1.3.2

Describe the bug

A clear and concise description of what the bug is.

To Reproduce

package main

import (
	"github.com/gookit/rux"
)
func main() {
	r := rux.New()
	
	r.GET(`/blog/{id:\d+}`, func(c *rux.Context) {
        c.Text(200, "view detail, id: " + c.Param("id"))
	})
	r.Listen(":8080")
}

Expected behavior
404
A clear and concise description of what you expected to happen.
/blog/100/ not match r.GET(/blog/{id:\d+})

Screenshots

If applicable, add screenshots to help explain your problem.

Additional context

Add any other context about the problem here.

支持embed文件

前端工程编译到static目录,里面包含html、js等,一般都需要把这些文件做embed,这样携带方便。我看目前所有的StaticXXX接口都不支持此类embed,这个能支持吗?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.