Lightning Fast HTTP Multiplexer

bone GoDoc Build Status Go Report Card

What is bone ?

Bone is a lightweight and lightning fast HTTP Multiplexer for Golang. It support :

  • URL Parameters
  • REGEX Parameters
  • Wildcard routes
  • Router Prefix
  • Route params validators
  • Sub Router, mux.SubRoute(), support most standard router (bone, gorilla/mux, httpRouter etc...)
  • Http method declaration
  • Support for http.Handler and http.HandlerFunc
  • Custom NotFound handler
  • Respect the Go standard http.Handler interface

alt tag

Speed

- BenchmarkBoneMux        10000000               118 ns/op
- BenchmarkZeusMux          100000               144 ns/op
- BenchmarkHttpRouterMux  10000000               134 ns/op
- BenchmarkNetHttpMux      3000000               580 ns/op
- BenchmarkGorillaMux       300000              3333 ns/op
- BenchmarkGorillaPatMux   1000000              1889 ns/op

These tests are just for fun, all these routers are great and efficient. Bone isn't the fastest router for every job.

Example

package main

import(
  "net/http"

  "github.com/go-zoo/bone"
)

func main () {
  mux := bone.New()

  mux.RegisterValidatorFunc("isNum", func(s string) bool {
    if _, err := strconv.Atoi(s); err == nil {
      return true
    }
    return false
  })

  // mux.Get, Post, etc ... takes http.Handler
  // validator for route parameter
  mux.Get("/home/:id|isNum", http.HandlerFunc(HomeHandler))
  // multiple parameter
  mux.Get("/profil/:id/:var", http.HandlerFunc(ProfilHandler))
  mux.Post("/data", http.HandlerFunc(DataHandler))

  // Support REGEX Route params
  mux.Get("/index/#id^[0-9]$", http.HandlerFunc(IndexHandler))

  // Handle take http.Handler
  mux.Handle("/", http.HandlerFunc(RootHandler))

  // GetFunc, PostFunc etc ... takes http.HandlerFunc
  mux.GetFunc("/test", Handler)

  http.ListenAndServe(":8080", mux)
}

func Handler(rw http.ResponseWriter, req *http.Request) {
  // Get the value of the "id" parameters.
  val := bone.GetValue(req, "id")

  rw.Write([]byte(val))
}

Blog Posts

Libs

  • Errors dump for Go : Trash
  • Middleware Chaining module : Claw
Owner
Comments
  • Concurrent map read and map write under Go 1.6.0

    Concurrent map read and map write under Go 1.6.0

    Since Go 1.6.0 and the concurrent acces detector, my app crashes under heavy load:

    fatal error: concurrent map read and map write
    

    at github.com/go-zoo/bone/route.go:98

    Does anybody else is experiencing the same issue ?

  • Panic running example 001

    Panic running example 001

    I got panic running example code:

    % go run 001/example.go -race
    
    2015/10/03 20:58:39 http: panic serving [::1]:45814: runtime error: invalid memory address or nil pointer dereference
    goroutine 182 [running]:
    net/http.(*conn).serve.func1(0xc8201786e0, 0x7f33df087650, 0xc820080398)
            /usr/lib/go/src/net/http/server.go:1287 +0xb5
    github.com/go-zoo/bone.(*Route).Match(0xc8200b0c80, 0xc820171880, 0xc820083a00)
            /tmp/b/src/github.com/go-zoo/bone/route.go:101 +0x28f
    github.com/go-zoo/bone.(*Mux).parse(0xc820076cf0, 0x7f33df0877d0, 0xc820178790, 0xc820171880, 0x0)
            /tmp/b/src/github.com/go-zoo/bone/helper.go:29 +0x31d
    github.com/go-zoo/bone.(*Mux).ServeHTTP(0xc820076cf0, 0x7f33df0877d0, 0xc820178790, 0xc820171880)
            /tmp/b/src/github.com/go-zoo/bone/bone.go:49 +0x43
    net/http.serverHandler.ServeHTTP(0xc8200700c0, 0x7f33df0877d0, 0xc820178790, 0xc820171880)
            /usr/lib/go/src/net/http/server.go:1862 +0x19e
    net/http.(*conn).serve(0xc8201786e0)
            /usr/lib/go/src/net/http/server.go:1361 +0xbee
    created by net/http.(*Server).Serve
            /usr/lib/go/src/net/http/server.go:1910 +0x3f6
    

    tested with curl:

    % (repeat 100 {curl localhost:8080/home/foo & })
    
  • 404 Error instead of 405 Status Code

    404 Error instead of 405 Status Code

    mux := bone.New()
    mux.Get("/test/", http.HandlerFunc(myHandler))
    

    If I make requests to /test/ endpoint with POST method then I get 404 Not Found error instead of 405 Method Not Allowed.

    Probable reason: map[string][]*Route the key in this map is method name (e.g., GET, POST, etc..) and the requested endpoint is searched in the slice of the requested method, and if the endpoint is not found then 404 is returned.

    Proposed Solution:

    1. Search all Method's slices. (too costly operation) OR
    2. Register routes with the different way.
  • More comprehensive benchmarks.

    More comprehensive benchmarks.

    Your benchmarks are comparing the fetching of a single url - This is a misleading benchmark which is heavily biased towards bone because of its simple algorithm.

    Please add some benchmarks where the number of routes is medium and large with varying degrees of shared prefixes.

  • case insensitive urls

    case insensitive urls

    Is there any support for using case insensitive urls?

    Say I have a page at http://test.com/promo/ and the user types http://test.com/Promo/ I would like it to still match.

    Sorry if there is a feature I am missing that allows for this.

  • Subrouter path issue

    Subrouter path issue

         mux := bone.New()
    
        sub := bone.New()
    
        sub.GetFunc("/test/example", func(rw http.ResponseWriter, req *http.Request) {
            rw.Write([]byte("From Sub router !"))
        })
    
        mux.Get("/api", sub)
    

    This is example from Readme, and it doesn't work. But example 003 in examples folder, works. Only difference is the path of the subrouter. If subrouter has more than 1 hardcoded pathsegments, it doesn't work. Example - "/test/example" Doesn't work. Whereas this - "/user/:id" works.

  • Issue with bone.GetVars()

    Issue with bone.GetVars()

    Just a quick thought.

    Example:

    runtime.GOMAXPROCS(2)
    mux.Get("/home/:id", Handler)
    

    And as http.ListenAndServe() emits each client in the separate goroutine, it might happen that two clients access /home/1 and /home/2 at the same time.

    According to the variant of the GetValue() as a global var , it I'm not sure that both clients will get the correct bone.GetValue("id").

  • go 1.7 context

    go 1.7 context

    Refactor value storage to use net.Context. This allows users of bone to use http.Request.WithContext without bone breaking.

    I also expect this to have performance benefits since the map of requests has been completely eliminated (and locking is no longer required, since we don't allow mutations of the request values).

  • getRequestRoute for subroutes

    getRequestRoute for subroutes

    Using getRequestRoute for sub routes isn't working properly. Let's assume I have the following setup:

    func Main() {
        mux := bone.New()
        mux.SubRoute("/v0", apiMux)
        http.ListenAndServe("127.0.0.1:3000", mux)
    }
    

    apiMux have the following endpoints registered:

    apiMux.Post("/users", usersHandler)
    apiMux.Post("/posts", postsHandler)
    

    Doing a request to /users will generate a http.Request with an URL equal to /v0/users. Calling getRequestRoute(req) returns /v0. I'd assume it returns /v0/users or /users.

    Is this a bug? If so, how do we want to fix it? I'd be happy to help in any way possible.

  • Query string not working in nested routers

    Query string not working in nested routers

    I have a sub route like:

    subRouter.GetFunc("*/users", ...)
    mainRouter.Get("/app/*", subRouter)
    

    This matches /app/users, but I can't figure out how to match the same path with an added query string. e.g. /app/users?active=true or /app/users?foo=1&bar=3

    I just get 404s. When I use a query string in the main router it works, but somehow a sub router fails. Any clues?

  • Are sub-routers or router-groups possible?

    Are sub-routers or router-groups possible?

    Like for instance the following:

    subRouter := bone.New()
    subRouter.GetFunc("/getNames", GetUserNamesControllerFunc)
    subRouter.GetFunc("/getEmail", GetUserEmailControllerFunc)
    
    router.Handle("/user", subRouter)
    

    I would like this code to handle the /user/getNames and /user/getEmail urls but it does not work. Is this functionality supported?

  • /api/home/  with   trail slash   should be  not found

    /api/home/ with trail slash should be not found

    package main
    
    import (
    	"encoding/json"
    	"fmt"
    	"log"
    	"net/http"
    	"time"
    
    	"github.com/go-zoo/bone"
    )
    
    var (
    	mux = bone.New(Serve, Wrap)
    )
    
    func Wrap(mux *bone.Mux) *bone.Mux {
    	return mux.Prefix("/api")
    }
    
    func Serve(mux *bone.Mux) *bone.Mux {
    	mux.Serve = func(rw http.ResponseWriter, req *http.Request) {
    		tr := time.Now()
    		mux.DefaultServe(rw, req)
    		fmt.Println("Serve request from", req.RemoteAddr, "in", time.Since(tr))
    	}
    	return mux
    }
    
    func main() {
    	// Custom 404
    	mux.NotFoundFunc(Handler404)
    	// Handle with any http method, Handle takes http.Handler as argument.
    	mux.Handle("/index", http.HandlerFunc(homeHandler))
    	mux.Handle("/index/:var/info/:test", http.HandlerFunc(varHandler))
    	// Get, Post etc... takes http.HandlerFunc as argument.
    	mux.Post("/home", http.HandlerFunc(homeHandler))
    	mux.Get("/home/:var", http.HandlerFunc(varHandler))
    
    	mux.GetFunc("/test/*", func(rw http.ResponseWriter, req *http.Request) {
    		rw.Write([]byte(req.RequestURI))
    	})
    
    	// Start Listening
    	log.Fatal(mux.ListenAndServe(":8080"))
    }
    
    func homeHandler(rw http.ResponseWriter, req *http.Request) {
    	rw.Write([]byte("WELCOME HOME"))
    }
    
    func varHandler(rw http.ResponseWriter, req *http.Request) {
    	varr := bone.GetValue(req, "var")
    	test := bone.GetValue(req, "test")
    
    	var args = struct {
    		First  string
    		Second string
    	}{varr, test}
    
    	if err := json.NewEncoder(rw).Encode(&args); err != nil {
    		panic(err)
    	}
    }
    
    func Handler404(rw http.ResponseWriter, req *http.Request) {
    	rw.Write([]byte("These are not the droids you're looking for ..."))
    }
    

    visist http://localhost:8080/api/home/xxx
    {"First":"xxx","Second":""} visit http://localhost:8080/api/home/ {"First":"","Second":""}

  • Include Allow header with 405 response

    Include Allow header with 405 response

    When bone returns a 405 Method Not Allowed response, it would be good if it could include an Allow header detailing which methods are permitted.

    I think it could perhaps be done by amending the otherMethods helper. Something like:

    func (m *Mux) otherMethods(rw http.ResponseWriter, req *http.Request) bool {
    	allowed := []string{}
    	for _, met := range method {
    		if met != req.Method {
    			for _, r := range m.Routes[met] {
    				ok := r.exists(rw, req)
    				if ok {
    					allowed = append(allowed, r.Method)
    				}
    			}
    		}
    	}
    	if len(allowed) > 0 {
    		rw.Header()["Allow"] = allowed
    		rw.WriteHeader(http.StatusMethodNotAllowed)
    		return true
    	}
    	return false
    }
    

    Also, what are your thoughts on including a plain text "Method Not Allowed" message in the response body, similar to the "404 page not allowed" body for 404s?

Related tags
Goji is a minimalistic and flexible HTTP request multiplexer for Go (golang)

Goji Goji is a HTTP request multiplexer, similar to net/http.ServeMux. It compares incoming requests to a list of registered Patterns, and dispatches

Jan 6, 2023
Go Server/API micro framework, HTTP request router, multiplexer, mux
Go Server/API micro framework, HTTP request router, multiplexer, mux

?? gorouter Go Server/API micro framework, HTTP request router, multiplexer, mux. ?? ABOUT Contributors: Rafał Lorenz Want to contribute ? Feel free t

Dec 16, 2022
FastRouter is a fast, flexible HTTP router written in Go.

FastRouter FastRouter is a fast, flexible HTTP router written in Go. FastRouter contains some customizable options, such as TrailingSlashesPolicy, Pan

Sep 27, 2022
:rotating_light: Is a lightweight, fast and extensible zero allocation HTTP router for Go used to create customizable frameworks.
:rotating_light: Is a lightweight, fast and extensible zero allocation HTTP router for Go used to create customizable frameworks.

LARS LARS is a fast radix-tree based, zero allocation, HTTP router for Go. view examples. If looking for a more pure Go solution, be sure to check out

Dec 27, 2022
An extremely fast Go (golang) HTTP router that supports regular expression route matching. Comes with full support for building RESTful APIs.

ozzo-routing You may consider using go-rest-api to jumpstart your new RESTful applications with ozzo-routing. Description ozzo-routing is a Go package

Dec 31, 2022
Pure is a fast radix-tree based HTTP router
Pure is a fast radix-tree based HTTP router

package pure Pure is a fast radix-tree based HTTP router that sticks to the native implementations of Go's "net/http" package; in essence, keeping the

Dec 1, 2022
xujiajun/gorouter is a simple and fast HTTP router for Go. It is easy to build RESTful APIs and your web framework.

gorouter xujiajun/gorouter is a simple and fast HTTP router for Go. It is easy to build RESTful APIs and your web framework. Motivation I wanted a sim

Dec 8, 2022
Fast and flexible HTTP router
Fast and flexible HTTP router

treemux - fast and flexible HTTP router Basic example Debug logging CORS example Error handling Rate limiting using Redis Gzip compression OpenTelemet

Dec 27, 2022
Fast, simple, and lightweight HTTP router for Golang

Sariaf Fast, simple and lightweight HTTP router for golang Install go get -u github.com/majidsajadi/sariaf Features Lightweight compatible with net/ht

Aug 19, 2022
Simple Golang HTTP router
Simple Golang HTTP router

Bellt Simple Golang HTTP router Bellt Package implements a request router with the aim of managing controller actions based on fixed and parameterized

Sep 27, 2022
A high performance HTTP request router that scales well

HttpRouter HttpRouter is a lightweight high performance HTTP request router (also called multiplexer or just mux for short) for Go. In contrast to the

Dec 28, 2022
High-speed, flexible tree-based HTTP router for Go.

httptreemux High-speed, flexible, tree-based HTTP router for Go. This is inspired by Julien Schmidt's httprouter, in that it uses a patricia tree, but

Dec 28, 2022
A powerful HTTP router and URL matcher for building Go web servers with 🦍

gorilla/mux https://www.gorillatoolkit.org/pkg/mux Package gorilla/mux implements a request router and dispatcher for matching incoming requests to th

Jan 9, 2023
Composable framework for writing HTTP handlers in Go.

siesta Siesta is a framework for writing composable HTTP handlers in Go. It supports typed URL parameters, middleware chains, and context passing. Get

Nov 18, 2022
Go HTTP router

violetear Go HTTP router http://violetear.org Design Goals Keep it simple and small, avoiding extra complexity at all cost. KISS Support for static an

Dec 10, 2022
lightweight, idiomatic and composable router for building Go HTTP services

chi is a lightweight, idiomatic and composable router for building Go HTTP services. It's especially good at helping you write large REST API services

Jan 8, 2023
:tongue: CleverGo is a lightweight, feature rich and high performance HTTP router for Go.

CleverGo CleverGo is a lightweight, feature rich and trie based high performance HTTP request router. go get -u clevergo.tech/clevergo English 简体中文 Fe

Nov 17, 2022
Mux is a simple and efficient route distributor that supports the net/http interface of the standard library.

Mux Mux is a simple and efficient route distributor that supports the net/http interface of the standard library. Routing data is stored in the prefix

Dec 12, 2022
Simple router build on `net/http` supports custom middleWare.

XMUS-ROUTER Fast lightweight router build on net/http supports delegate and in url params. usage : Create new router using NewRouter() which need rout

Dec 27, 2021