Coder Social home page Coder Social logo

mux's Introduction

mux

Build Status Coverage Status GoDoc

A high performance and powerful trie based url path router for Go.

This router supports fixed and regex rules in routing pattern, and matches request method. It's optimized by trie structure for faster matching and large scale rules.

requirement: Go 1.7+

Feature

todo

Usage

This is a simple example for mux. Read godoc to get full api documentation.

There is a basic example:

package main

import (
    	"fmt"
	"log"
	"net/http"

	"github.com/beego/mux"
)

func main() {
	mx := mux.New()
	mx.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello, beego mux"))
	})
	mx.Get("/abc/:id", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "hello, abc page %s", mux.Param(r,":id"))
	})

	log.Fatal(http.ListenAndServe("127.0.0.1:9999", mx))
}

Register route mapping as http.HandleFunc via http method name:

mx.Get("/get", getHandleFunc)
mx.Post("/post", postHandleFunc)
mx.Put("/put", putHandleFunc)
mx.Delete("/delete", deleteHandleFunc)
mx.Head("/head", headHandleFunc)
mx.Options("/options", optionsHandleFunc)
mx.Patch("/patch", patchHandleFunc)

Or use raw api to add route with http method name:

mx.Handle("GET", "/abc", abcHandleFunc)

Register http.Handle.

mx2 := mux.New()
mx.Get("/ttt", getHandleFunc)
mx.Handler("GET","/abc", mx2) // /abc/ttt -> getHandleFunc

default handler

Register default handle to resolve missing matches. If can not find matched pattern, mux runs default handler if set.

mx.Get("/abc",abcHandleFunc)
mx.DefaultHandler(defaultHandleFunc)
// abc -> abcHandleFunc
// ^abc -> defaultHandleFunc

Routing

The routing pattern can set as fixed pattern as most simple way. When using fixed pattern, it supports to parse json, xml and html extension to match pattern.

Pattern: /abc/xyz

/abc/xyz        matched
/abc/xyz.html   matched 
/abc/xyz.json   matched 
/abc/xyz.xml    matched 
/abc/xzz        no matched

But in common cases, you need parameters to match differenct segments in path.

Named parameters

As you see, :id is a named parameter. The matched parameters can read one via mux.Param method from *http.Request by parameter's name.

// r is *http.Request
fmt.Println(mux.Param(r,":id"))

Or read all parameters by mux.Params.

// r is *http.Request
fmt.Println(mux.Params(r))
// e.g. map[:id:1 :name:beego]

A named parameter only can match single segment of path with extension.

Pattern: /abc/:id

/abc/           no match
/abc/123        matched     (:id is 123)
/abc/xyz        matched     (:id is xyz)
/abc/123/xyz    no matched
/abc/123.html   matched     (:id is 123.html)

Wildcard parameters

If you need to match several segments in path, use * and *.* named wildcard parameters.

* matches all segments between previous and next segment node in pattern. The matched segement parts are stored in params with key :splat.

Pattern: /abc/*/xyz

/abc/xyz                no match
/abc/123/xyz            matched     (:splat is 123)
/abc/12/34/xyz          matched     (:splat is 12/34)  

*.* has familar behaviour with *, but matched results are two parts, :path as path segment and :ext as extension suffix.

Pattern : /abc/*.*

/abc/xyz.json           matched     (:path is xyz, :ext is json)
/abc/123/xyz.html       matched     (:path is 123/xyz, :ext is html)

Regexp parameters

mux supports a regular expression as a paramter , named regexp paramaters. You can set a regexp into pattern with a name placeholder.

Pattern : /abc/:id([0-9]+)

/abc/123                matched     (:id is 123)
/abc/xyz                no matched

You can set value type for one named paramater to simplify some common regexp rules. Now support :int ([0-9]+) and :string ([\w]+).

Pattern: /abc/:id:int

/abc/123        matched (:id is 123)
/abc/xyz        no match

Regexp paramters can match several parts in one segment in path.

Pattern: /abc/article_:id:int

/abc/123            no matched
/abc/article_123    matched     (:id is 123)
/abc/article_xyz    no matched

Optional parameters

If the parameter can be not found in pattern when matching url, use ? to declare this situation. ? support named and regexp parameters.

Pattern: /abc/xyz/?:id

/abc/xyz/               matched     (:id is empty)
/abc/xyz/123            matched     (:id is 123)
Pattern: /abc/xyz/?:id:int

/abc/xyz/               matched     (:id is empty)
/abc/xyz/123            matched     (:id is 123)
/abc/xyz/aaa            no matched

Complex patterns

The fixed segements, named parameters and regexp patterns can be used in one rule together.

Pattern: /article/:id/comment_:page:int

/article/12/comment_2       matched     (:id is 12, :page is 2)
/article/abc/comment_3      matched     (:id is abc, :page is 3)
/article/abc/comment_xyz    no match
Pattern: /data/:year/*/list

/data/2012/11/12/list       matched     (:year is 2012, :splat is 11/12)
/data/2014/12/list          matched     (:year is 2014, :splat is 12)
Pattern: /pic/:width:int/:height:int/*.*

/pic/20/20/aaaaaa.jpg      matched     (:width is 20, :height is 20, :path is aaaaaa, :ext is jpg)

pattern matching order

Static pattern > parameters' pattern > regexp pattern.

URL : /abc/99

pattern: /abc/99            matched
pattern: /abc/:id           no match
pattern: /abc/:id:int       no match

URL : /abc/123

pattern: /abc/99            no match
pattern: /abc/:id           matched    (:id is 123)
pattern: /abc/:id:int       no match

If register confusing patterns, it matches first one in adding order. For example, in regexp patterns:

mx := mux.New()

mx.Get("/abc/?:id:int", func(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "abc, int params %v", mux.Params(r))
})
mx.Get("/abc/?:name:string", func(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "abc, string params %v", mux.Params(r))
})

mx.Get("/xyz/?:name:string", func(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "xyz, string params %v", mux.Params(r))
})
mx.Get("/xyz/?:id:int", func(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "xyz, int params %v", mux.Params(r))
})

When using this mx to match urls, it shows result:

URL				Pattern
/abc		->		/abc/?:id:int			(first one)
/abc/123	->		/abc/?:id:int
/abc/zzz	->		/abc/?:name:string

/xyz		->		/xyz/?:name:string		(first one)
/xyz/123	->		/xyz/?:name:string		(123 is treated as string "123")
/xyz/zzz	->		/xyz/?:name:string

mux's People

Contributors

appleboy avatar astaxie avatar fuxiaohei avatar xiocode 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  avatar  avatar  avatar

Watchers

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

mux's Issues

router not work as expected

I add some test code in the test file https://github.com/beego/mux/blob/master/mux_test.go#L21

t.Run("router with wildcard pattern2", func(t *testing.T) {
	assert := assert.New(t)

	mux := New()

	mux.Get("/a/:a/b", func(w http.ResponseWriter, r *http.Request) {
		params := Params(r)
		w.WriteHeader(200)
		w.Write([]byte(params[":a"]))
	})
	mux.Get("/a/:a/b/:b", func(w http.ResponseWriter, r *http.Request) {
		params := Params(r)
		w.WriteHeader(200)
		w.Write([]byte(params[":a"]))
	})
	mux.Get("/a/:a/b/:b/c", func(w http.ResponseWriter, r *http.Request) {
		params := Params(r)
		w.WriteHeader(200)
		w.Write([]byte(params[":a"]))
	})

	ts := httptest.NewServer(mux)
	defer ts.Close()

	res, err := Request("GET", ts.URL+"/a/a1/b/b1/c", nil)
	assert.Nil(err)
	assert.Equal(200, res.StatusCode)
	body, _ := ioutil.ReadAll(res.Body)
	assert.Equal("a1", string(body))
	res.Body.Close()
})

1 .It didn't pass the test, "/a/a1/b/b1/c" not match pattern "/a/:a/b/:b/c"
2. I change the route order, let pattern "/a/:a/b/:b/c" to be first defined router, and it matches, but
"/a/a1/b/b1" not match pattern "/a/:a/b/:b"

It just passes ok in httprouter , is that a bug of mux?

route mapping works wrong when pattern segments has ":name" type

My test enviroment:
os:

mac os x and ubuntu 16.04

go:

$go version
go version go1.8 darwin/amd64

beego/mux version:

commit 38fddcbf1be964bbc26c0cf7b91157719cfdb56f

test code:

package main

import (
    "log"
    "net/http"

    "github.com/beego/mux"
)

func Register(method string, pattern string, handler http.HandlerFunc) {
    mx.Handler(method, pattern, handler)
}

func addServer(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("addServer"))
}

func getServer(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("getServer"))
}

func delServer(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("delServer"))
}

var mx *mux.Mux

func main() {
    mx = mux.New()

    Register("POST", "/api/v1/servers/:server_name", addServer)
    Register("DELETE", "/api/v1/servers/:server_name", delServer)
    Register("GET", "/api/v1/servers/:server_name", getServer)

    log.Fatal(http.ListenAndServe("127.0.0.1:9999", mx))
}

result:

$curl -X POST  http://127.0.0.1:9999/api/v1/servers/yy-pd.com
addServer

$curl http://127.0.0.1:9999/api/v1/servers/yy-pd.com
"GET" not allowed in "/api/v1/servers/yy-pd.com"

$curl -X DELETE  http://127.0.0.1:9999/api/v1/servers/yy-pd.com
"DELETE" not allowed in "/api/v1/servers/yy-pd.com"

expected: all curl command should return right result.

segments after ":name" type will match wrong

there are two conflict router:

GET /v1/team/:tid/duty
GET /v1/team/:svc/info

the secode route will not match

package main

import (
	"log"
	"net/http"

	"github.com/beego/mux"
)

func main() {
	m := mux.New()
	m.Get("/v1/team/:tid/duty", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello, beego mux\n"))
	})
	m.Get("/v1/team/:svc/info", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello, beego mux 2\n"))
	})

	log.Fatal(http.ListenAndServe("127.0.0.1:2222", m))
}

curl:

mozhata@pc:try$ curl http://127.0.0.1:2222/v1/team/ididid/duty
hello, beego mux
mozhata@pc:try$ curl http://127.0.0.1:2222/v1/team/ididid/info
"/v1/team/ididid/info" not implemented

but replace :svc to :tid, these two routes all works

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.