trie

package module
v1.5.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 10, 2021 License: MIT Imports: 4 Imported by: 7

README

trie-mux

A minimal and powerful trie based url path router (or mux) for Go.

Build Status Coverage Status License GoDoc

JavaScript Version

https://github.com/zensh/route-trie

Features

  1. Support named parameter (package trie)
  2. Support regexp (package trie)
  3. Support suffix matching (package trie)
  4. Fixed path automatic redirection (package trie)
  5. Trailing slash automatic redirection (package trie)
  6. Automatic handle 405 Method Not Allowed (package mux)
  7. Automatic handle 501 Not Implemented (package mux)
  8. Automatic handle OPTIONS method (package mux)
  9. Best Performance

Implementations

trie-mux: mux.Mux

https://github.com/teambition/trie-mux/blob/master/mux/mux.go

package main

import (
  "fmt"
  "io/ioutil"
  "net/http"
  "net/http/httptest"

  "github.com/teambition/trie-mux/mux"
)

func main() {
  router := mux.New()
  router.Get("/", func(w http.ResponseWriter, _ *http.Request, _ mux.Params) {
    w.Header().Set("Content-Type", "text/html; charset=utf-8")
    w.WriteHeader(200)
    w.Write([]byte("<h1>Hello, Gear!</h1>"))
  })

  router.Get("/view/:view", func(w http.ResponseWriter, _ *http.Request, params mux.Params) {
    view := params["view"]
    if view == "" {
      http.Error(w, "Invalid view", 400)
    } else {
      w.Header().Set("Content-Type", "text/html; charset=utf-8")
      w.WriteHeader(200)
      w.Write([]byte("View: " + view))
    }
  })

  // srv := http.Server{Addr: ":3000", Handler: router}
  // srv.ListenAndServe()
  srv := httptest.NewServer(router)
  defer srv.Close()

  res, _ := http.Get(srv.URL + "/view/users")
  body, _ := ioutil.ReadAll(res.Body)
  res.Body.Close()

  fmt.Println(res.StatusCode, string(body))
  // Output: 200 View: users
}
Gear: gear.Router

https://github.com/teambition/gear/blob/master/router.go

package main

import (
  "fmt"
  "io/ioutil"
  "net/http"

  "github.com/teambition/gear"
)

func main() {
  app := gear.New()

  router := gear.NewRouter()
  router.Get("/", func(ctx *gear.Context) error {
    return ctx.HTML(200, "<h1>Hello, Gear!</h1>")
  })
  router.Get("/view/:view", func(ctx *gear.Context) error {
    view := ctx.Param("view")
    if view == "" {
      return &gear.Error{Code: 400, Msg: "Invalid view"}
    }
    return ctx.HTML(200, "View: "+view)
  })

  app.UseHandler(router)
  srv := app.Start(":3000")
  defer srv.Close()

  res, _ := http.Get("http://" + srv.Addr().String() + "/view/users")
  body, _ := ioutil.ReadAll(res.Body)
  res.Body.Close()

  fmt.Println(res.StatusCode, string(body))
  // Output: 200 View: users
}

Pattern Rule

The defined pattern can contain six types of parameters:

Syntax Description
:name named parameter
:name(regexp) named with regexp parameter
:name+suffix named parameter with suffix matching
:name(regexp)+suffix named with regexp parameter and suffix matching
:name* named with catch-all parameter
::name not named parameter, it is literal :name

Named parameters are dynamic path segments. They match anything until the next '/' or the path end:

Defined: /api/:type/:ID

/api/user/123             matched: type="user", ID="123"
/api/user                 no match
/api/user/123/comments    no match

Named with regexp parameters match anything using regexp until the next '/' or the path end:

Defined: /api/:type/:ID(^\d+$)

/api/user/123             matched: type="user", ID="123"
/api/user                 no match
/api/user/abc             no match
/api/user/123/comments    no match

Named parameters with suffix, such as Google API Design:

Defined: /api/:resource/:ID+:undelete

/api/file/123                     no match
/api/file/123:undelete            matched: resource="file", ID="123"
/api/file/123:undelete/comments   no match

Named with regexp parameters and suffix:

Defined: /api/:resource/:ID(^\d+$)+:cancel

/api/task/123                   no match
/api/task/123:cancel            matched: resource="task", ID="123"
/api/task/abc:cancel            no match

Named with catch-all parameters match anything until the path end, including the directory index (the '/' before the catch-all). Since they match anything until the end, catch-all parameters must always be the final path element.

Defined: /files/:filepath*

/files                           no match
/files/LICENSE                   matched: filepath="LICENSE"
/files/templates/article.html    matched: filepath="templates/article.html"

The value of parameters is saved on the Matched.Params. Retrieve the value of a parameter by name:

type := matched.Params("type")
id   := matched.Params("ID")

Url query string with ? can be provided when defining trie, but it will be ignored.

Defined: /files?pageSize=&pageToken= Equal to: /files

/files                           matched, query string will be ignored
/files/LICENSE                   no match

Documentation

https://godoc.org/github.com/teambition/trie-mux

Bench

go test -bench=. ./mux
GithubAPI Routes: 203
   trie-mux: 37464 Bytes
   HttpRouter: 37464 Bytes
   httptreemux: 78768 Bytes
BenchmarkTrieMux-4                    20000      758711 ns/op   1082902 B/op      2974 allocs/op
BenchmarkHttpRouter-4                 20000      687400 ns/op   1030826 B/op      2604 allocs/op
BenchmarkHttpTreeMux-4                20000      786506 ns/op   1082902 B/op      3108 allocs/op
BenchmarkTrieMuxRequests-4             1000    17564036 ns/op    816398 B/op     10488 allocs/op
BenchmarkHttpRouterRequests-4          1000    17050872 ns/op    764200 B/op     10117 allocs/op
BenchmarkHttpTreeMuxRequests-4         1000    17125625 ns/op    816408 B/op     10622 allocs/op
PASS
ok    github.com/teambition/trie-mux/mux  96.427s

License

trie-mux is licensed under the MIT license. Copyright © 2016-2017 Teambition.

Documentation

Overview

Package trie implements a minimal and powerful trie based url path router (or mux) for Go.

Index

Constants

View Source
const Version = "1.5.2"

Version is trie-mux version

Variables

This section is empty.

Functions

This section is empty.

Types

type Matched

type Matched struct {
	// Either a Node pointer when matched or nil
	Node *Node

	// Either a map contained matched values or empty map.
	Params map[string]string

	// If FixedPathRedirect enabled, it may returns a redirect path,
	// otherwise a empty string.
	FPR string

	// If TrailingSlashRedirect enabled, it may returns a redirect path,
	// otherwise a empty string.
	TSR string
}

Matched is a result returned by Trie.Match.

type Node

type Node struct {
	// contains filtered or unexported fields
}

Node represents a node on defined patterns that can be matched.

func (*Node) GetAllow added in v1.1.0

func (n *Node) GetAllow() string

GetAllow returns allow methods defined on the node

trie := New()
trie.Define("/").Handle("GET", handler1)
trie.Define("/").Handle("PUT", handler2)

// trie.Match("/").Node.GetAllow() == "GET, PUT"

func (*Node) GetDescendants added in v1.5.0

func (n *Node) GetDescendants() []*Node

GetDescendants returns all descendants nodes.

func (*Node) GetHandler added in v1.1.0

func (n *Node) GetHandler(method string) interface{}

GetHandler ... GetHandler returns handler by method that defined on the node

trie := New()
trie.Define("/api").Handle("GET", func handler1() {})
trie.Define("/api").Handle("PUT", func handler2() {})

trie.Match("/api").Node.GetHandler("GET").(func()) == handler1
trie.Match("/api").Node.GetHandler("PUT").(func()) == handler2

func (*Node) GetMethods added in v1.5.0

func (n *Node) GetMethods() []string

GetMethods returns methods defined on the node

func (*Node) GetPattern added in v1.4.2

func (n *Node) GetPattern() string

GetPattern returns pattern defined on the node

func (*Node) Handle

func (n *Node) Handle(method string, handler interface{})

Handle is used to mount a handler with a method name to the node.

t := New()
node := t.Define("/a/b")
node.Handle("GET", handler1)
node.Handle("POST", handler1)

type Options

type Options struct {
	// Ignore case when matching URL path.
	IgnoreCase bool

	// If enabled, the trie will detect if the current path can't be matched but
	// a handler for the fixed path exists.
	// Matched.FPR will returns either a fixed redirect path or an empty string.
	// For example when "/api/foo" defined and matching "/api//foo",
	// The result Matched.FPR is "/api/foo".
	FixedPathRedirect bool

	// If enabled, the trie will detect if the current path can't be matched but
	// a handler for the path with (without) the trailing slash exists.
	// Matched.TSR will returns either a redirect path or an empty string.
	// For example if /foo/ is requested but a route only exists for /foo, the
	// client is redirected to /foo
	// For example when "/api/foo" defined and matching "/api/foo/",
	// The result Matched.TSR is "/api/foo".
	TrailingSlashRedirect bool
}

Options is options for Trie.

type Trie

type Trie struct {
	// contains filtered or unexported fields
}

Trie represents a trie that defining patterns and matching URL.

func New

func New(args ...Options) *Trie

New returns a trie

trie := New()
// disable IgnoreCase, TrailingSlashRedirect and FixedPathRedirect
trie := New(Options{})

func (*Trie) Define

func (t *Trie) Define(pattern string) *Node

Define define a pattern on the trie and returns the endpoint node for the pattern.

trie := New()
node1 := trie.Define("/a")
node2 := trie.Define("/a/b")
node3 := trie.Define("/a/b")
// node2.parent == node1
// node2 == node3

The defined pattern can contain three types of parameters:

| Syntax | Description | |--------|------| | `:name` | named parameter | | `:name*` | named with catch-all parameter | | `:name(regexp)` | named with regexp parameter | | `::name` | not named parameter, it is literal `:name` |

func (*Trie) GetEndpoints added in v1.5.0

func (t *Trie) GetEndpoints() []*Node

GetEndpoints returns all endpoint nodes.

func (*Trie) Match

func (t *Trie) Match(path string) *Matched

Match try to match path. It will returns a Matched instance that includes *Node, Params and Tsr flag when matching success, otherwise a nil.

matched := trie.Match("/a/b")

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL