{"id":13694205,"url":"https://github.com/xujiajun/gorouter","last_synced_at":"2025-04-04T08:06:27.397Z","repository":{"id":57481819,"uuid":"119361250","full_name":"xujiajun/gorouter","owner":"xujiajun","description":"xujiajun/gorouter is a simple and fast HTTP router for Go. It is easy to build RESTful APIs and your web framework.","archived":false,"fork":false,"pushed_at":"2019-09-27T07:07:43.000Z","size":137,"stargazers_count":531,"open_issues_count":0,"forks_count":70,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-03-28T07:05:36.665Z","etag":null,"topics":["go","golang","gorouter","restful-api","router"],"latest_commit_sha":null,"homepage":"https://xujiajun.cn/gorouter","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xujiajun.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-01-29T09:28:28.000Z","updated_at":"2025-01-16T03:07:29.000Z","dependencies_parsed_at":"2022-09-02T06:04:04.282Z","dependency_job_id":null,"html_url":"https://github.com/xujiajun/gorouter","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xujiajun%2Fgorouter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xujiajun%2Fgorouter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xujiajun%2Fgorouter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xujiajun%2Fgorouter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xujiajun","download_url":"https://codeload.github.com/xujiajun/gorouter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247142049,"owners_count":20890652,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","gorouter","restful-api","router"],"created_at":"2024-08-02T17:01:26.763Z","updated_at":"2025-04-04T08:06:27.380Z","avatar_url":"https://github.com/xujiajun.png","language":"Go","readme":"# gorouter  [![GoDoc](https://godoc.org/github.com/xujiajun/gorouter?status.svg)](https://godoc.org/github.com/xujiajun/gorouter) \u003ca href=\"https://travis-ci.org/xujiajun/gorouter\"\u003e\u003cimg src=\"https://travis-ci.org/xujiajun/gorouter.svg?branch=master\" alt=\"Build Status\"\u003e\u003c/a\u003e [![Go Report Card](https://goreportcard.com/badge/github.com/xujiajun/gorouter)](https://goreportcard.com/report/github.com/xujiajun/gorouter) [![Coverage Status](https://s3.amazonaws.com/assets.coveralls.io/badges/coveralls_100.svg)](https://coveralls.io/github/xujiajun/gorouter?branch=master) [![License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://raw.githubusercontent.com/xujiajun/gorouter/master/LICENSE)  [![Release](https://img.shields.io/badge/release-v1.1.0-blue.svg?style=flat-square)](https://github.com/xujiajun/gorouter/releases/tag/v1.0.1) [![Awesome](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go#routers) \n`xujiajun/gorouter` is a simple and fast HTTP router for Go. It is easy to build RESTful APIs and your web framework.\n\n## Motivation\n\nI wanted a simple and fast HTTP GO router, which supports regexp. I prefer to support regexp is because otherwise it will need the logic to check the URL parameter type, thus increasing the program complexity. So I did some searching on Github and found the wonderful `julienschmidt/httprouter`: it is very fast，unfortunately it does not support regexp. Later I found out about `gorilla/mux`: it is powerful as well，but a written benchmark shows me that it is somewhat slow. So I tried to develop a new router which both supports regexp and should be fast. Finally I did it and named `xujiajun/gorouter`. By the way, this is my first GO open source project. It may be the fastest GO HTTP router which supports regexp, and regarding its performance please refer to my latest [Benchmarks](#benchmarks).\n\n## Features\n\n* Fast - see [Benchmarks](#benchmarks)\n* [URL parameters](#url-parameters)\n* [Regex parameters](#regex-parameters)\n* [Routes groups](#routes-groups)\n* [Reverse Routing](#reverse-routing)\n* [Custom NotFoundHandler](#custom-notfoundhandler)\n* [Custom PanicHandler](#custom-panichandler)\n* [Middleware Chain Support](#middlewares-chain)\n* [Serve Static Files](#serve-static-files)\n* [Pattern Rule Familiar](#pattern-rule)\n* HTTP Method Get、Post、Delete、Put、Patch Support\n* No external dependencies (just Go stdlib)\n\n\n## Requirements\n\n* golang 1.8+\n\n## Installation\n\n```\ngo get -u github.com/xujiajun/gorouter\n```\n\n## Usage\n\n### Static routes\n\n```golang\npackage main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/xujiajun/gorouter\"\n)\n\nfunc main() {\n\tmux := gorouter.New()\n\tmux.GET(\"/\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"hello world\"))\n\t})\n\tlog.Fatal(http.ListenAndServe(\":8181\", mux))\n}\n\n```\n\n### URL Parameters\n\n```golang\npackage main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/xujiajun/gorouter\"\n)\n\nfunc main() {\n\tmux := gorouter.New()\n\t//url parameters match\n\tmux.GET(\"/user/:id\", func(w http.ResponseWriter, r *http.Request) {\n\t\t//get one URL parameter\n\t\tid := gorouter.GetParam(r, \"id\")\n\t\t//get all URL parameters\n\t\t//id := gorouter.GetAllParams(r)\n\t\t//fmt.Println(id)\n\t\tw.Write([]byte(\"match user/:id ! get id:\" + id))\n\t})\n\n\tlog.Fatal(http.ListenAndServe(\":8181\", mux))\n}\n```\n\n### Regex Parameters\n\n```golang\npackage main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/xujiajun/gorouter\"\n)\n\nfunc main() {\n\tmux := gorouter.New()\n\t//url regex match\n\tmux.GET(\"/user/{id:[0-9]+}\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"match user/{id:[0-9]+} !\"))\n\t})\n\n\tlog.Fatal(http.ListenAndServe(\":8181\", mux))\n}\n```\n\n\n### Routes Groups\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/xujiajun/gorouter\"\n)\n\nfunc usersHandler(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprint(w, \"/api/users\")\n}\n\nfunc main() {\n\tmux := gorouter.New()\n\tmux.Group(\"/api\").GET(\"/users\", usersHandler)\n\n\tlog.Fatal(http.ListenAndServe(\":8181\", mux))\n}\n```\n\n### Reverse Routing\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/xujiajun/gorouter\"\n)\n\nfunc main() {\n\tmux := gorouter.New()\n\n\trouteName1 := \"user_event\"\n\tmux.GETAndName(\"/users/:user/events\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"/users/:user/events\"))\n\t}, routeName1)\n\n\trouteName2 := \"repos_owner\"\n\tmux.GETAndName(\"/repos/{owner:\\\\w+}/{repo:\\\\w+}\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"/repos/{owner:\\\\w+}/{repo:\\\\w+}\"))\n\t}, routeName2)\n\n\tparams := make(map[string]string)\n\tparams[\"user\"] = \"xujiajun\"\n\tfmt.Println(mux.Generate(http.MethodGet, routeName1, params)) // /users/xujiajun/events \u003cnil\u003e\n\n\tparams = make(map[string]string)\n\tparams[\"owner\"] = \"xujiajun\"\n\tparams[\"repo\"] = \"xujiajun_repo\"\n\tfmt.Println(mux.Generate(http.MethodGet, routeName2, params)) // /repos/xujiajun/xujiajun_repo \u003cnil\u003e\n}\n\n```\n\n### Custom NotFoundHandler\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/xujiajun/gorouter\"\n)\n\nfunc notFoundFunc(w http.ResponseWriter, r *http.Request) {\n\tw.WriteHeader(http.StatusNotFound)\n\tfmt.Fprint(w, \"404 page !!!\")\n}\n\nfunc main() {\n\tmux := gorouter.New()\n\tmux.NotFoundFunc(notFoundFunc)\n\tmux.GET(\"/\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"hello world\"))\n\t})\n\n\tlog.Fatal(http.ListenAndServe(\":8181\", mux))\n}\n```\n\n### Custom PanicHandler\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/xujiajun/gorouter\"\n)\n\nfunc main() {\n\tmux := gorouter.New()\n\tmux.PanicHandler = func(w http.ResponseWriter, req *http.Request, err interface{}) {\n\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\tfmt.Println(\"err from recover is :\", err)\n\t\tfmt.Fprint(w, \"received a panic\")\n\t}\n\tmux.GET(\"/panic\", func(w http.ResponseWriter, r *http.Request) {\n\t\tpanic(\"panic\")\n\t})\n\n\tlog.Fatal(http.ListenAndServe(\":8181\", mux))\n}\n\n```\n\n### Middlewares Chain\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/xujiajun/gorouter\"\n)\n\ntype statusRecorder struct {\n\thttp.ResponseWriter\n\tstatus int\n}\n\nfunc (rec *statusRecorder) WriteHeader(code int) {\n\trec.status = code\n\trec.ResponseWriter.WriteHeader(code)\n}\n\n//https://upgear.io/blog/golang-tip-wrapping-http-response-writer-for-middleware/\nfunc withStatusRecord(next http.HandlerFunc) http.HandlerFunc {\n\treturn func(w http.ResponseWriter, r *http.Request) {\n\t\trec := statusRecorder{w, http.StatusOK}\n\t\tnext.ServeHTTP(\u0026rec, r)\n\t\tlog.Printf(\"response status: %v\\n\", rec.status)\n\t}\n}\n\nfunc notFoundFunc(w http.ResponseWriter, r *http.Request) {\n\tw.WriteHeader(http.StatusNotFound)\n\tfmt.Fprint(w, \"Not found page !\")\n}\n\nfunc withLogging(next http.HandlerFunc) http.HandlerFunc {\n\treturn func(w http.ResponseWriter, r *http.Request) {\n\t\tlog.Printf(\"Logged connection from %s\", r.RemoteAddr)\n\t\tnext.ServeHTTP(w, r)\n\t}\n}\n\nfunc withTracing(next http.HandlerFunc) http.HandlerFunc {\n\treturn func(w http.ResponseWriter, r *http.Request) {\n\t\tlog.Printf(\"Tracing request for %s\", r.RequestURI)\n\t\tnext.ServeHTTP(w, r)\n\t}\n}\n\nfunc main() {\n\tmux := gorouter.New()\n\tmux.NotFoundFunc(notFoundFunc)\n\tmux.Use(withLogging, withTracing, withStatusRecord)\n\tmux.GET(\"/\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"hello world\"))\n\t})\n\n\tlog.Fatal(http.ListenAndServe(\":8181\", mux))\n}\n```\n\n## Serve static files\n\n```golang\npackage main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\n\t\"github.com/xujiajun/gorouter\"\n)\n\n//ServeFiles serve static resources\nfunc ServeFiles(w http.ResponseWriter, r *http.Request) {\n\twd, err := os.Getwd()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tdir := wd + \"/examples/serveStaticFiles/files\"\n\thttp.StripPrefix(\"/files/\", http.FileServer(http.Dir(dir))).ServeHTTP(w, r)\n}\n\nfunc main() {\n\tmux := gorouter.New()\n\tmux.GET(\"/hi\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"hi\"))\n\t})\n\t//defined prefix\n\tmux2 := mux.Group(\"/files\")\n\t//http://127.0.0.1:8181/files/demo.txt\n\t//will match\n\tmux2.GET(\"/{filename:[0-9a-zA-Z_.]+}\", func(w http.ResponseWriter, r *http.Request) {\n\t\tServeFiles(w, r)\n\t})\n\n\t//http://127.0.0.1:8181/files/a/demo2.txt\n\t//http://127.0.0.1:8181/files/a/demo.txt\n\t//will match\n\tmux2.GET(\"/{fileDir:[0-9a-zA-Z_.]+}/{filename:[0-9a-zA-Z_.]+}\", func(w http.ResponseWriter, r *http.Request) {\n\t\tServeFiles(w, r)\n\t})\n\n\tlog.Fatal(http.ListenAndServe(\":8181\", mux))\n}\n```\nDetail see [serveStaticFiles example](https://github.com/xujiajun/gorouter/blob/master/examples/serveStaticFiles/main.go)\n\n## Pattern Rule\n\nThe syntax here is modeled after [julienschmidt/httprouter](https://github.com/julienschmidt/httprouter) and [gorilla/mux](https://github.com/gorilla/mux)\n\n| Syntax | Description | Example |\n|--------|------|-------|\n| `:name` | named parameter | /user/:name |\n| `{name:regexp}` | named with regexp parameter |  /user/{name:[0-9a-zA-Z]+} |\n| `:id` | named with regexp parameter |  /user/:id |\n\nAnd `:id` is short for `{id:[0-9]+}`, `:name` are short for `{name:[0-9a-zA-Z_]+}`\n\n\u003e if use default regex checks unless you know what you're doing\n\n \n## Benchmarks\n\nthe benchmarks code for gorouter be found in the [gorouter-bench](https://github.com/xujiajun/gorouter-bench) repository.\n\n\u003e go test -bench=.\n\n### Benchmark System:\n\n* Go Version : go1.11.2 darwin/amd64\n* OS:        Mac OS X 10.13.6\n* Architecture:   x86_64\n* 16 GB 2133 MHz LPDDR3\n* CPU: 3.1 GHz Intel Core i7\n\n### Tested routers:\n\n* [beego/mux](https://github.com/beego/mux)\n* [go-zoo/bone](https://github.com/go-zoo/bone)\n* [go-chi/chi](https://github.com/go-chi/chi)\n* [julienschmidt/httprouter](https://github.com/julienschmidt/httprouter)\n* [gorilla/mux](https://github.com/gorilla/mux)\n* [trie-mux/mux](https://github.com/teambition/trie-mux)\n* [xujiajun/gorouter](https://github.com/xujiajun/gorouter)\n\n\nThanks the author of httprouter: [@julienschmidt](https://github.com/julienschmidt) give me advise about benchmark [issues/24](https://github.com/xujiajun/gorouter/issues/24)\n\n## Result:\n\nGiven some routing matching syntax differences, divide GithubAPI into two groups：\n\n### Using GithubAPI Result：\n\n```\nBenchmarkBeegoMuxRouterWithGithubAPI-8   \t   10000\t    142398 ns/op\t  134752 B/op\t    1038 allocs/op\nBenchmarkBoneRouterWithGithubAPI-8       \t    1000\t   2104486 ns/op\t  720160 B/op\t    8620 allocs/op\nBenchmarkTrieMuxRouterWithGithubAPI-8    \t   20000\t     80845 ns/op\t   65856 B/op\t     537 allocs/op\nBenchmarkHttpRouterWithGithubAPI-8       \t   50000\t     30169 ns/op\t   13792 B/op\t     167 allocs/op\nBenchmarkGoRouter1WithGithubAPI-8        \t   30000\t     57793 ns/op\t   13832 B/op\t     406 allocs/op\n\n```\n### Using GithubAPI2 Result：\n\n```\nBenchmarkGoRouter2WithGithubAPI2-8       \t   30000\t     57613 ns/op\t   13832 B/op\t     406 allocs/op\nBenchmarkChiRouterWithGithubAPI2-8       \t   10000\t    143224 ns/op\t  104436 B/op\t    1110 allocs/op\nBenchmarkMuxRouterWithGithubAPI2-8       \t     300\t   4450731 ns/op\t   61463 B/op\t     995 allocs/op\n```\n\n### All togther Result：\n\n```\n➜  gorouter git:(master) go test -bench=.\nGithubAPI Routes: 203\nGithubAPI2 Routes: 203\n   BeegoMuxRouter: 111072 Bytes\n   BoneRouter: 100992 Bytes\n   ChiRouter: 71512 Bytes\n   HttpRouter: 37016 Bytes\n   trie-mux: 131128 Bytes\n   MuxRouter: 1378496 Bytes\n   GoRouter1: 83824 Bytes\n   GoRouter2: 85584 Bytes\ngoos: darwin\ngoarch: amd64\npkg: github.com/xujiajun/gorouter\nBenchmarkBeegoMuxRouterWithGithubAPI-8   \t   10000\t    142398 ns/op\t  134752 B/op\t    1038 allocs/op\nBenchmarkBoneRouterWithGithubAPI-8       \t    1000\t   2104486 ns/op\t  720160 B/op\t    8620 allocs/op\nBenchmarkTrieMuxRouterWithGithubAPI-8    \t   20000\t     80845 ns/op\t   65856 B/op\t     537 allocs/op\nBenchmarkHttpRouterWithGithubAPI-8       \t   50000\t     30169 ns/op\t   13792 B/op\t     167 allocs/op\nBenchmarkGoRouter1WithGithubAPI-8        \t   30000\t     57793 ns/op\t   13832 B/op\t     406 allocs/op\nBenchmarkGoRouter2WithGithubAPI2-8       \t   30000\t     57613 ns/op\t   13832 B/op\t     406 allocs/op\nBenchmarkChiRouterWithGithubAPI2-8       \t   10000\t    143224 ns/op\t  104436 B/op\t    1110 allocs/op\nBenchmarkMuxRouterWithGithubAPI2-8       \t     300\t   4450731 ns/op\t   61463 B/op\t     995 allocs/op\nPASS\nok  \tgithub.com/xujiajun/gorouter\t15.918s\n\n```\n\n### Conclusions:\n\n* Performance (xujiajun/gorouter,julienschmidt/httprouter and teambition/trie-mux are fast)\n\n* Memory Consumption (xujiajun/gorouter and julienschmidt/httprouter are fewer) \n\n* Features (julienschmidt/httprouter not supports regexp，but others support it)\n\n\u003e if you want a high performance router which supports regexp, maybe [xujiajun/gorouter](https://github.com/xujiajun/gorouter) is good choice.\n\n\u003e if you want a high performance router which not supports regexp, maybe [julienschmidt/httprouter](https://github.com/julienschmidt/httprouter) is good choice.\n\nIn the end, as julienschmidt 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.`\n\n## Contributing\n\nIf you'd like to help out with the project. You can put up a Pull Request. Thanks to all [contributors](https://github.com/xujiajun/gorouter/graphs/contributors).\n\n## Author\n\n* [xujiajun](https://github.com/xujiajun)\n\n## License\n\nThe gorouter is open-sourced software licensed under the [MIT Licensed](http://www.opensource.org/licenses/MIT)\n\n## Acknowledgements\n\nThis package is inspired by the following:\n\n* [httprouter](https://github.com/julienschmidt/httprouter)\n* [bone](https://github.com/go-zoo/bone)\n* [trie-mux](https://github.com/teambition/trie-mux)\n* [alien](https://github.com/gernest/alien)\n","funding_links":[],"categories":["Web Frameworks","Go","Routers","路由","Web框架","Repositories"],"sub_categories":["Routers","创建http中间件的代码库","路由器"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxujiajun%2Fgorouter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxujiajun%2Fgorouter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxujiajun%2Fgorouter/lists"}