rhttp

package module
v0.0.0-...-019ff40 Latest Latest
Warning

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

Go to latest
Published: Oct 8, 2013 License: BSD-3-Clause Imports: 8 Imported by: 0

README

rhttp

Regexp routing for go http

Package rhttp provides a means for routing http requests from the http package to handlers registered to match a particular regular expression. The routing mechanism is fully compatible with the http package and is designed to complement, not replace it.

Routing

RegexpRouter implements http.Handler and can therefore be registered on a pattern as any other handler. However, RegexpRouter also exposes methods similar to http.ServeMux allowing a rhttp.Handler to be registered on a regular expression. For example:

    type DoParams struct {
        Var string `rhttp:"var"`
    }
    func Do(w http.ResponseWriter, r *http.Request, i interface{}) {
        params := i.(*DoParams)
        w.Write([]byte(params.Var))
    }
    func main() {
        router := rhttp.NewRouter()
        router.HandleFunc("/re/(var=.*)", Do, &DoParams{})
        http.Handle("/re/", router)
        ...
    }

A simple syntax for defining routes is used where a variable name is followed by an = and a regular expression, all surrounded by parenthesis. For example:

    /static/(var_name=re)/static(/?)

The variable name is optional; its omission results in an anonymous group which is not represented in the parameters passed back to the Handler. This may be useful for matching on a path whether or not the trailing / is present. Note that as a consequence of the syntax, an anonymous group may not contain and = in its regular expression. As a work around, a dummy variable will need to be used.

Variable naming follows the same rules as go.

Parts of the pattern outside the groups are not parsed as regular expressions. If needed, these parts may contain escape sequences \(, \\, or \) to insert the corresponding character into the path. Variable names may not be escaped, and regular expressions obey the usual escaping rules.

One important difference between http and rhttp is the precedence of routes. http uses a longest wins approach. This doesn't make sense for patterns containing regular expressions. In fact, two very different regular expressions could potentially both match a path.

Like http, rhttp also uses longest wins at the prefix level. The prefix is from the beginning of the pattern until the first group. If multiple patterns have the same prefix, the earliest registered pattern will take precedence and be tested first. If the pattern fails, the next earliest registered pattern with the same prefix will be tried, and so forth until all registered patterns have been exhausted.

Variable Resolution

Reflection is used to determine a scope for variable names appearing in the pattern. At registration, an otherwise unused struct is provided as a final argument. The router will traverse the fields of the struct searching for rhttp tags:

    struct {
        Var string `rhttp:"var"`
    }

Only exported fields (those beginning with a capital letter) can be used. Tagged fields must be of type int, uint, float or string, and the string inside the tag must be a valid variable name as described above. Failure to meet these conditions will result in a run time panic.

Untagged fields are also considered if they are of an allowed type and the name does not conflict with a manually tagged field.

Any variable names used in a pattern must be present in the scope defined by the struct. The variables are also typed. If a pattern is matched but does not type match, the route is not taken.

Documentation

Index

Examples

Constants

View Source
const (
	Unterminated errorCause = iota
	MissingVariableName
	InvalidVariableName
	UndefinedVariable
	UnmatchedRightParen
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Handler

type Handler interface {
	ServeHTTP(http.ResponseWriter, *http.Request, interface{})
}

Analogous to http.Handler, ServeHTTP will be called with an empty interface which can be cast to the type the Handler was registered with.

type HandlerFunc

type HandlerFunc func(http.ResponseWriter, *http.Request, interface{})

func (HandlerFunc) ServeHTTP

func (f HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request, params interface{})

type PatternCompileError

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

func (*PatternCompileError) Error

func (err *PatternCompileError) Error() string

type RegexpRouter

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

A http.Handler that will take the usual http request and response and re-route it to the appropriate rhttp.Handler.

Example
w := new(ResponseWriterMock)
type P struct {
	S string `rhttp:"s"`
}

f := func(w http.ResponseWriter, r *http.Request, i interface{}) {
	params := i.(*P)
	fmt.Printf("%s\n", params.S)
}

router := NewRouter()
router.HandleFunc("/(s=[abc])", f, &P{})

r, _ := http.NewRequest("GET", "/a", strings.NewReader(""))
router.ServeHTTP(w, r)

r, _ = http.NewRequest("GET", "/b", strings.NewReader(""))
router.ServeHTTP(w, r)

w.WriteHeader(0)
r, _ = http.NewRequest("GET", "/d", strings.NewReader(""))
router.ServeHTTP(w, r)
fmt.Printf("%d\n", w.GetCode())
Output:

a
b
404

func NewRouter

func NewRouter() *RegexpRouter

Create a new Router

func (*RegexpRouter) Handle

func (r *RegexpRouter) Handle(pattern string, handler Handler, params interface{})

Registers a Handler with the RegexpRouter.

func (*RegexpRouter) HandleFunc

func (r *RegexpRouter) HandleFunc(pattern string, f func(http.ResponseWriter, *http.Request, interface{}), params interface{})

An adapter allowing an appropriate function to also be registered.

func (*RegexpRouter) ServeHTTP

func (r *RegexpRouter) ServeHTTP(w http.ResponseWriter, req *http.Request)

Reroute the request to the appropriate rhttp.Handler using req.Path

Jump to

Keyboard shortcuts

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