Coder Social home page Coder Social logo

gorilla / muxy Goto Github PK

View Code? Open in Web Editor NEW
74.0 19.0 11.0 51 KB

Package gorilla/muxy takes gorilla/mux to the next level

Home Page: https://gorilla.github.io

License: BSD 3-Clause "New" or "Revised" License

Go 100.00%
go golang gorilla gorilla-web-toolkit mux mux-router

muxy's People

Contributors

biw avatar garyburd avatar moraes 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

Watchers

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

muxy's Issues

Middleware

Some questions to get the ball rolling on this:

  • What signature should we accept?
  • Single middleware? Variadic?
  • Where does the method sit?

Also take a look at what alice and negroni do—although I think the latter is too centered on its own HandlerFunc type to be useful.


My thoughts:

  • My experience here is that func(http.Handler) http.Handler has become the 'defacto' standard.
  • Variadic. Chaining Use(auth).Use(csrf).Use(logging) is clunky and serves little benefit.
  • router.Use(middleware ...func(http.Handler) http.Handler) — keep it simple.

Middleware should apply to all routes below it (no exceptions), and sub-routers (however they shake out) should be able to apply additional middleware (e.g. auth) of their own.

Concurrent Middleware

Hi,

I would like to help with your development if it's possible and I've also been thinking, if it's worth having, concurrent middleware. If the middleware function returns a channel then it will be a concurrent middleware and the Handle will be executed when all concurrent middleware finished.

Discussion: Top-Level Router API

Might as well start this to pick up where gorilla/mux#130 leaves off.

Some high-level comments:

  • func (r *Route) Handler(handler http.HandlerFunc, methods ...string) *Route should accept a http.Handler and have a sister method HandleFunc that accepts a http.HandleFunc.
  • Not sure where this puts the Get, Head, etc. convenience methods—additional methods for these would clutter the API.
  • Should router.Sub return a *Router instead, allowing you to use the same methods as you would on a *Router? prefix could be a field of Router that the call to router.Sub sets.

Initial benchmarks

Here are some initial benchmarks comparing gorilla/mux, httprouter and gorilla/muxy.

Note: muxy is not even done with optimizations yet, and specially no static matching optimizations were applied so far (I have a plan for them).

Matching with 1 variable
gorilla/mux          200000              6650 ns/op             832 B/op         11 allocs/op
httprouter          5000000               278 ns/op              32 B/op          1 allocs/op
gorilla/muxy       10000000               220 ns/op               0 B/op          0 allocs/op
---------------------------------------------------------------------------------------------
Matching with 5 variables
gorilla/mux          100000             12260 ns/op            1088 B/op         19 allocs/op
httprouter          2000000               718 ns/op             160 B/op          1 allocs/op
gorilla/muxy        3000000               463 ns/op               0 B/op          0 allocs/op
---------------------------------------------------------------------------------------------
Matching with 20 variables
gorilla/mux           50000             29081 ns/op            3931 B/op         51 allocs/op
httprouter          1000000              2065 ns/op             640 B/op          1 allocs/op
gorilla/muxy        1000000              1616 ns/op               0 B/op          0 allocs/op
---------------------------------------------------------------------------------------------       
Matching all static
gorilla/mux             500           3632207 ns/op           71520 B/op       1192 allocs/op
httprouter            50000             30321 ns/op               0 B/op          0 allocs/op
gorilla/muxy          30000             50069 ns/op               0 B/op          0 allocs/op
---------------------------------------------------------------------------------------------
GitHub API - Matching with variables
gorilla/mux          100000             25261 ns/op             896 B/op         13 allocs/op
httprouter          2000000               639 ns/op              96 B/op          1 allocs/op
gorilla/muxy        3000000               459 ns/op               0 B/op          0 allocs/op
---------------------------------------------------------------------------------------------
GitHub API - Matching static
gorilla/mux           50000             35582 ns/op             480 B/op          8 allocs/op
httprouter         20000000               123 ns/op               0 B/op          0 allocs/op
gorilla/muxy       10000000               174 ns/op               0 B/op          0 allocs/op
---------------------------------------------------------------------------------------------
GitHub API - Matching all
gorilla/mux             100          13680783 ns/op          167232 B/op       2469 allocs/op
httprouter            10000            118606 ns/op           13792 B/op        167 allocs/op
gorilla/muxy          20000            101905 ns/op               0 B/op          0 allocs/op
---------------------------------------------------------------------------------------------
Google Plus API - Matching with 1 variable
gorilla/mux          200000              9200 ns/op             832 B/op         11 allocs/op
httprouter          3000000               458 ns/op              64 B/op          1 allocs/op
gorilla/muxy        5000000               241 ns/op               0 B/op          0 allocs/op
---------------------------------------------------------------------------------------------
Google Plus API - Matching with 2 variables
gorilla/mux          100000             20531 ns/op             896 B/op         13 allocs/op
httprouter          3000000               537 ns/op              64 B/op          1 allocs/op
gorilla/muxy        3000000               381 ns/op               0 B/op          0 allocs/op
---------------------------------------------------------------------------------------------
Google Plus API - Matching static
gorilla/mux          500000              4070 ns/op             480 B/op          8 allocs/op
httprouter         20000000              69.4 ns/op               0 B/op          0 allocs/op
gorilla/muxy       10000000               117 ns/op               0 B/op          0 allocs/op
---------------------------------------------------------------------------------------------
Google Plus API - Matching all
gorilla/mux           10000            148108 ns/op           10432 B/op        147 allocs/op
httprouter           300000              5983 ns/op             640 B/op         11 allocs/op
gorilla/muxy         300000              4140 ns/op               0 B/op          0 allocs/op
---------------------------------------------------------------------------------------------
Parse API - Matching with 1 variable
gorilla/mux          200000              7645 ns/op             832 B/op         11 allocs/op
httprouter          3000000               406 ns/op              64 B/op          1 allocs/op
gorilla/muxy        5000000               305 ns/op               0 B/op          0 allocs/op
---------------------------------------------------------------------------------------------
Parse API - Matching with 2 variables
gorilla/mux          200000              9020 ns/op             896 B/op         13 allocs/op
httprouter          3000000               459 ns/op              64 B/op          1 allocs/op
gorilla/muxy        3000000               376 ns/op               0 B/op          0 allocs/op
---------------------------------------------------------------------------------------------
Parse API - Matching static 
gorilla/mux          200000              6260 ns/op             480 B/op          8 allocs/op
httprouter         20000000                73.5 ns/op             0 B/op          0 allocs/op
gorilla/muxy       10000000               218 ns/op               0 B/op          0 allocs/op
---------------------------------------------------------------------------------------------
Parse API - Matching all
gorilla/mux            5000            284016 ns/op           18304 B/op        262 allocs/op
httprouter           200000              8605 ns/op             640 B/op         16 allocs/op
gorilla/muxy         200000              9465 ns/op               0 B/op          0 allocs/op

Discussion: why not a custom handler signature?

The title says it all: I'd like to hear your opinions about the pros and cons to stay with the func(http.ResponseWriter, *http.Request) signature for handlers, and why not set one that accepts an extra variables parameter.

match null value

package main

import (
    "io"
    "net/http"

    "github.com/gorilla/muxy"
)

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

    router.Route("/{a}/{b}").Get(func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "/{a}/{b}")
    })

    router.Route("/{a}/{b}/{c}").Get(func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "/{a}/{b}/{c}")
    })

    http.ListenAndServe(":80", router)
}
/{a}/{b} match //
/{a}/{b}/{c} match ///

as expected?

/{*} mismatch

    router := muxy.New()
    router.Route("/{*}").Get(func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "/{*}")
    })
    router.Route("/{a}/{b}").Get(func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "/{a}/{b}")
    })
    http.ListenAndServe(":80", router)

/{a}/{b} match /a/b
/{*} mismatch /a

Proposal: Only support http.Handler + Go 1.7

https://tip.golang.org/doc/go1.7#context

Go 1.7's http.Request now has a Context() context.Context method. We can now rely on this to pass route/pattern/match information alongside a request and remove the need to use interface{} for handling different handler signatures.

Major benefits:

  • Compile time type-safety again with http.Handler
  • Better docs (no interface{})
  • Supported by default in Go 1.7 onwards.

e.g.

- func (r *Route) Get(h interface{}) *Route
+ func (r *Route) Get(h http.Handler) *Route

type Matcher interface {
   ...
-    Match(c context.Context, r *http.Request) (context.Context, Handler)
+    Match(r *http.Request) (*http.Request, Handler)
   ...
} 

- func Var(c context.Context, name string) string
+ func Var(r *http.Request, name string) string

gorilla/mux can continue to support older applications, and you could potentially use build tags to fall back to using gorilla/context for <= Go 1.6 as I did with the csrf package: gorilla/csrf#35

@moraes - not sure on your thoughts here and/or whether you want to pick up work on this again.

Discussion: Subrouting

I detected two kinds of subrouting that we may want to support:

  1. Convenience setup for path and name prefix: when defining several routes that share a path or name prefix, it is nice to have a way to define the shared prefix once, then define the remaining based on that "subroute". It's avoids repeating yourself and also makes a bit easier to refactor a route setup;
  2. Mount (or "import") routes defined in a different package: as requested in gorilla/mux#136, this allows packages to define their routes independently. Then a main package imports the defined routers or setup mounting points for them;

These are somewhat related. The first one is simply "nice to have"; the second is not a so common use case, but why not? In any case, the first can be used by the second when mounting a foreign router in a given path. The docs for Mount() illustrate it better:

// Mount imports all routes from the given router into this one.
//
// Combined with Sub() and Name(), it is possible to submount a router
// defined in a different package using pattern and name prefixes:
//
//     r := New()
//     s := r.Sub("/admin").Name("admin:").Mount(admin.Router)
func (r *Router) Mount(router *Router) *Router {

These two kinds of subrouting require the three router methods exemplified in the docs above: Sub() (which creates a subrouter for a pattern prefix), Name() (sets a name prefix for the routes), and Mount() (imports routes defined elsewhere).

Given this initial draft, I invite you to share your thoughts about the subject.

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.