gorouter

package module
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Feb 23, 2018 License: MIT Imports: 5 Imported by: 0

README

gorouter GoDoc Build Status Go Report Card Coverage Status

A simple and fast HTTP router for Go.

Motivation

I wanted a simple, fast router that has no unnecessary overhead using the standard library only, following good practices and well tested code.

Features

  • Fast - see benchmarks
  • URL parameters
  • Regex parameters
  • Routes groups
  • Custom NotFoundHandler
  • Middleware chain Support
  • No external dependencies (just Go 1.7+ stdlib)

Installation

go get github.com/xujiajun/gorouter

Usage

Static routes
package main

import (
	"log"
	"net/http"
	"github.com/xujiajun/gorouter"
)

func main() {
	mux := gorouter.New()
	mux.GET("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world"))
	})
	log.Fatal(http.ListenAndServe(":8181", mux))
}

URL Parameters
package main

import (
	"github.com/xujiajun/gorouter"
	"log"
	"net/http"
)

func main() {
	mux := gorouter.New()
	//url parameters match
	mux.GET("/user/:id", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("match user/:id !"))
	})

	log.Fatal(http.ListenAndServe(":8181", mux))
}
Regex Parameters
package main

import (
	"github.com/xujiajun/gorouter"
	"log"
	"net/http"
)

func main() {
	mux := gorouter.New()
	//url regex match
	mux.GET("/user/{id:[0-9]+}", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("match user/{id:[0-9]+} !"))
	})

	log.Fatal(http.ListenAndServe(":8181", mux))
}
Group routes
package main

import (
	"fmt"
	"github.com/xujiajun/gorouter"
	"log"
	"net/http"
)

func usersHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, "/api/users")
}

func main() {
	mux := gorouter.New()
	mux.Group("/api").GET("/users", usersHandler)

	log.Fatal(http.ListenAndServe(":8181", mux))
}
Custom NotFoundHandler
package main

import (
	"fmt"
	"github.com/xujiajun/gorouter"
	"log"
	"net/http"
)

func notFoundFunc(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNotFound)
	fmt.Fprint(w, "404 page !!!")
}

func main() {
	mux := gorouter.New()
	mux.NotFoundFunc(notFoundFunc)
	mux.GET("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world"))
	})

	log.Fatal(http.ListenAndServe(":8181", mux))
}
Middlewares
package main

import (
	"fmt"
	"github.com/xujiajun/gorouter"
	"log"
	"net/http"
)

type statusRecorder struct {
	http.ResponseWriter
	status int
}

func (rec *statusRecorder) WriteHeader(code int) {
	rec.status = code
	rec.ResponseWriter.WriteHeader(code)
}

//https://upgear.io/blog/golang-tip-wrapping-http-response-writer-for-middleware/
func withStatusRecord(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		rec := statusRecorder{w, http.StatusOK}
		next.ServeHTTP(&rec, r)
		log.Printf("response status: %v\n", rec.status)
	}
}

func notFoundFunc(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNotFound)
	fmt.Fprint(w, "Not found page !")
}

func withLogging(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Printf("Logged connection from %s", r.RemoteAddr)
		next.ServeHTTP(w, r)
	}
}

func withTracing(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Printf("Tracing request for %s", r.RequestURI)
		next.ServeHTTP(w, r)
	}
}

func main() {
	mux := gorouter.New()
	mux.NotFoundFunc(notFoundFunc)
	mux.Use(withLogging, withTracing, withStatusRecord)
	mux.GET("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world"))
	})

	log.Fatal(http.ListenAndServe(":8181", mux))
}

Pattern Rule

The syntax here is modeled after julienschmidt/httprouter and gorilla/mux

Syntax Description Example
:name named parameter /user/:name
{name} named parameter /user/{name}
{name:regexp} named with regexp parameter /user/{name:[0-9a-zA-Z]+}
:id named with regexp parameter /user/:id

And :id is short for {id:[0-9]+}, {name} and :name are short for {name:[0-9a-zA-Z]+}

Benchmarks

go test -bench=.

Benchmark System:

  • Go version 1.9.2
  • OS: Mac OS X 10.13.3
  • Architecture: x86_64
  • 16 GB 2133 MHz LPDDR3

Tested routers:

Result:

GithubAPI Routes: 203
GithubAPI2 Routes: 203
   HttpRouter: 37464 Bytes
   GoRouter: 83616 Bytes
   MuxRouter: 1324192 Bytes
goos: darwin
goarch: amd64
pkg: github.com/xujiajun/gorouter
BenchmarkHttpRouter-8   	   10000	    517116 ns/op	 1034339 B/op	    2604 allocs/op
BenchmarkGoRouter-8     	   10000	    551223 ns/op	 1034385 B/op	    2843 allocs/op
BenchmarkMuxRouter-8    	   10000	   5825422 ns/op	 1272958 B/op	    4691 allocs/op
PASS
ok  	github.com/xujiajun/gorouter	68.965s

Conclusions:

  • Memory Consumption (HttpRouter > gorouter > MuxRouter)

  • Performance (HttpRouter > gorouter > MuxRouter)

  • Features (HttpRouter not support regexp, But GoRouter and MuxRouter support)

As author of HttpRouter said performance can not be the (only) criterion for choosing a router. Play around a bit with some of the routers, and choose the one you like best. Moreover main memory is cheap and usually not a scarce resource.

Contributing

If you'd like to help out with the project. You can put up a Pull Request.

Acknowledgements

This package is inspired by the following:

License

The gorouter is open-sourced software licensed under the MIT Licensed

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetAllParams

func GetAllParams(r *http.Request) paramsMapType

GetAllParams return all route params stored in r.

func GetParam

func GetParam(r *http.Request, key string) string

GetParam return route param stored in r.

Types

type Node

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

Node records any URL params, and executes an end handler.

func NewNode

func NewNode(key string, depth int) *Node

NewNode returns a newly initialized Node object that implements the Node

type Router

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

Router is a simple HTTP route multiplexer that parses a request path, records any URL params, and executes an end handler.

func New

func New() *Router

New returns a newly initialized Router object that implements the Router

func (*Router) DELETE

func (router *Router) DELETE(path string, handle http.HandlerFunc)

DELETE adds the route `path` that matches a DELETE http method to execute the `handle` http.HandlerFunc.

func (*Router) GET

func (router *Router) GET(path string, handle http.HandlerFunc)

GET adds the route `path` that matches a GET http method to execute the `handle` http.HandlerFunc.

func (*Router) Group

func (router *Router) Group(prefix string) *Router

Group define routes groups If there is a path prefix that use `prefix`

func (*Router) Handle

func (router *Router) Handle(method string, path string, handle http.HandlerFunc)

Handle registers a new request handle with the given path and method.

func (*Router) HandleNotFound

func (router *Router) HandleNotFound(w http.ResponseWriter, r *http.Request, middleware []middlewareType)

HandleNotFound registers a handler when the request route is not found

func (*Router) Match

func (router *Router) Match(requestUrl string, path string) bool

Match check if the request match the route Pattern

func (*Router) NotFoundFunc

func (router *Router) NotFoundFunc(handler http.HandlerFunc)

NotFoundFunc registers a handler when the request route is not found

func (*Router) PATCH

func (router *Router) PATCH(path string, handle http.HandlerFunc)

PATCH adds the route `path` that matches a PATCH http method to execute the `handle` http.HandlerFunc.

func (*Router) POST

func (router *Router) POST(path string, handle http.HandlerFunc)

POST adds the route `path` that matches a POST http method to execute the `handle` http.HandlerFunc.

func (*Router) PUT

func (router *Router) PUT(path string, handle http.HandlerFunc)

PUT adds the route `path` that matches a PUT http method to execute the `handle` http.HandlerFunc.

func (*Router) ServeHTTP

func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP makes the router implement the http.Handler interface.

func (*Router) Use

func (router *Router) Use(middleware ...middlewareType)

Use appends a middleware handler to the middleware stack.

type Tree

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

Tree records node

func NewTree

func NewTree() *Tree

NewTree returns a newly initialized Tree object that implements the Tree

func (*Tree) Add

func (tree *Tree) Add(pattern string, handle http.HandlerFunc, middleware ...middlewareType)

Add use `pattern` 、handle、middleware stack as node register to tree

func (*Tree) Find

func (tree *Tree) Find(pattern string, isRegex int) (nodes []*Node)

Find returns nodes that the request match the route pattern

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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