Songmu / goblin

A golang http router based on trie tree.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

goblin

CircleCI GitHub license

A golang http router based on trie tree.

Features

  • Go 1.13
  • Easy to use
  • Lightweight
  • Fully compatible with net/http
  • No external dependencies
  • Support named parameters with an optional regular expression.

Install

go get -u github.com/bmf-san/goblin

Usage

Basic

goblin supports these http methods.

GET/POST/PUT/PATCH/DELETE/OPTION

You can define routing like this.

r := goblin.NewRouter()

r.GET(`/`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "/")
}))

r.POST(`/`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "/")
}))

Named parameters

You can use named parameters like this.

r := goblin.NewRouter()

r.GET(`/foo/:id`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    id := goblin.GetParam(r.Context(), "id")
    fmt.Fprintf(w, "/foo/%v", id)
}))

r.POST(`/foo/:name`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    name := goblin.GetParam(r.Context(), "name")
    fmt.Fprintf(w, "/foo/%v", name)
}))

Named parameters with regular expression

You can also use named parameter with regular expression like this.

:paramName[pattern]

r.GET(`/foo/:id[^\d+$]`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    id := goblin.GetParam(r.Context(), "id")
    fmt.Fprintf(w, "/foo/%v", id)
}))

Since the default pattern is (.+), if you don't define it, then :id is defined as :id[(.+)].

Note

A routing pattern matching priority depends on an order of routing definition.

r := goblin.NewRouter()

r.GET(`/foo/:id`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, `/foo/:id`)
}))
r.GET(`/foo/:id[^\d+$]`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, `/foo/:id[^\d+$]`)
}))
r.GET(`/foo/:id[^\w+$]`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, `/foo/:id[^\w+$]`)
}))

If you want to define a route that matches anything, you can define it as follows.

r := goblin.NewRouter()

// This definition needs to be defined last for the most part. Otherwise, it will not match correctly.
// Incidentally, this can be used to deal with preflight.
r.OPTION(`:`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, `: metches anything`)
}))

Examples

package main

import (
	"fmt"
	"net/http"

	goblin "github.com/bmf-san/goblin"
)

func main() {
	r := goblin.NewRouter()

	r.GET(`/`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "/")
	}))
	r.GET(`/foo`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "/foo")
	}))
	r.GET(`/foo/bar`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "/foo/bar")
	}))
	r.GET(`/foo/bar/:id`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		id := goblin.GetParam(r.Context(), "id")
		fmt.Fprintf(w, "/foo/bar/%v", id)
	}))
	r.GET(`/foo/bar/:id/:name`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		id := goblin.GetParam(r.Context(), "id")
		name := goblin.GetParam(r.Context(), "name")
		fmt.Fprintf(w, "/foo/bar/%v/%v", id, name)
	}))
	r.GET(`/foo/:id[^\d+$]`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		id := goblin.GetParam(r.Context(), "id")
		fmt.Fprintf(w, "/foo/%v", id)
	}))
	r.GET(`/foo/:id[^\d+$]/:name`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		id := goblin.GetParam(r.Context(), "id")
		name := goblin.GetParam(r.Context(), "name")
		fmt.Fprintf(w, "/foo/%v/%v", id, name)
	}))

	http.ListenAndServe(":9999", r)
}

If you want to try it, you can use an _examples.

Benchmark

go version: 1.14

go test -bench=.

Run a total of 203 routes of GithubAPI.

Tested routes:

Memory Consumption:

goblin: 62896 Bytes
beego-mux: 107328 Bytes
HttpRouter: 37096 Bytes
httptreemux: 78896 Bytes
gin: 59128 Bytes
chi: 71528 Bytes

Benchmark Results:

BenchmarkGoblin-4                           1363            793539 ns/op         1056676 B/op       3455 allocs/op
BenchmarkBeegoMux-4                         1420            972325 ns/op         1142023 B/op       3475 allocs/op
BenchmarkHttpRouter-4                       1393            878506 ns/op         1021039 B/op       2604 allocs/op
BenchmarkHttpTreeMux-4                      1459            832753 ns/op         1073111 B/op       3108 allocs/op
BenchmarkGin-4                              1033            974177 ns/op         1014084 B/op       2642 allocs/op
BenchmarkChi-4                              1239            846166 ns/op         1095217 B/op       3047 allocs/op
BenchmarkGoblinRequests-4                     60          19327539 ns/op          884059 B/op      11221 allocs/op
BenchmarkBeegoMuxRequests-4                   58          19789097 ns/op          969311 B/op      11241 allocs/op
BenchmarkHttpRouterRequests-4                 58          21749265 ns/op          848012 B/op      10370 allocs/op
BenchmarkHttpTreeMuxRequests-4                57          24634215 ns/op          900326 B/op      10874 allocs/op
BenchmarkHttpGinRequests-4                    45          24686299 ns/op          840777 B/op      10405 allocs/op
BenchmarkHttpChiRequests-4                    45          22363389 ns/op          921963 B/op      10811 allocs/op

Router design

Router accepts requests and dispatches handlers.

architecture

goblin based on trie tree structure.

trie

Contribution

Please take a look at our CONTRIBUTING.md file.

License

This project is licensed under the terms of the MIT license.

Author

bmf - A Web Developer in Japan.

About

A golang http router based on trie tree.

License:MIT License


Languages

Language:Go 100.0%