github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/go-chi/chi/README.md (about) 1 # <img alt="chi" src="https://cdn.rawgit.com/go-chi/chi/master/_examples/chi.svg" width="220" /> 2 3 4 [![GoDoc Widget]][GoDoc] [![Travis Widget]][Travis] 5 6 `chi` is a lightweight, idiomatic and composable router for building Go 1.7+ HTTP services. It's 7 especially good at helping you write large REST API services that are kept maintainable as your 8 project grows and changes. `chi` is built on the new `context` package introduced in Go 1.7 to 9 handle signaling, cancelation and request-scoped values across a handler chain. 10 11 The focus of the project has been to seek out an elegant and comfortable design for writing 12 REST API servers, written during the development of the Pressly API service that powers our 13 public API service, which in turn powers all of our client-side applications. 14 15 The key considerations of chi's design are: project structure, maintainability, standard http 16 handlers (stdlib-only), developer productivity, and deconstructing a large system into many small 17 parts. The core router `github.com/go-chi/chi` is quite small (less than 1000 LOC), but we've also 18 included some useful/optional subpackages: [middleware](/middleware), [render](https://github.com/go-chi/render) and [docgen](https://github.com/go-chi/docgen). We hope you enjoy it too! 19 20 ## Install 21 22 `go get -u github.com/go-chi/chi` 23 24 25 ## Features 26 27 * **Lightweight** - cloc'd in ~1000 LOC for the chi router 28 * **Fast** - yes, see [benchmarks](#benchmarks) 29 * **100% compatible with net/http** - use any http or middleware pkg in the ecosystem that is also compatible with `net/http` 30 * **Designed for modular/composable APIs** - middlewares, inline middlewares, route groups and subrouter mounting 31 * **Context control** - built on new `context` package, providing value chaining, cancelations and timeouts 32 * **Robust** - in production at Pressly, CloudFlare, Heroku, 99Designs, and many others (see [discussion](https://github.com/go-chi/chi/issues/91)) 33 * **Doc generation** - `docgen` auto-generates routing documentation from your source to JSON or Markdown 34 * **No external dependencies** - plain ol' Go 1.7+ stdlib + net/http 35 36 37 ## Examples 38 39 * [rest](https://github.com/go-chi/chi/blob/master/_examples/rest/main.go) - REST APIs made easy, productive and maintainable 40 * [logging](https://github.com/go-chi/chi/blob/master/_examples/logging/main.go) - Easy structured logging for any backend 41 * [limits](https://github.com/go-chi/chi/blob/master/_examples/limits/main.go) - Timeouts and Throttling 42 * [todos-resource](https://github.com/go-chi/chi/blob/master/_examples/todos-resource/main.go) - Struct routers/handlers, an example of another code layout style 43 * [versions](https://github.com/go-chi/chi/blob/master/_examples/versions/main.go) - Demo of `chi/render` subpkg 44 * [fileserver](https://github.com/go-chi/chi/blob/master/_examples/fileserver/main.go) - Easily serve static files 45 * [graceful](https://github.com/go-chi/chi/blob/master/_examples/graceful/main.go) - Graceful context signaling and server shutdown 46 47 48 **As easy as:** 49 50 ```go 51 package main 52 53 import ( 54 "net/http" 55 "github.com/go-chi/chi" 56 ) 57 58 func main() { 59 r := chi.NewRouter() 60 r.Get("/", func(w http.ResponseWriter, r *http.Request) { 61 w.Write([]byte("welcome")) 62 }) 63 http.ListenAndServe(":3000", r) 64 } 65 ``` 66 67 **REST Preview:** 68 69 Here is a little preview of how routing looks like with chi. Also take a look at the generated routing docs 70 in JSON ([routes.json](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.json)) and in 71 Markdown ([routes.md](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.md)). 72 73 I highly recommend reading the source of the [examples](#examples) listed above, they will show you all the features 74 of chi and serve as a good form of documentation. 75 76 ```go 77 import ( 78 //... 79 "context" 80 "github.com/go-chi/chi" 81 "github.com/go-chi/chi/middleware" 82 ) 83 84 func main() { 85 r := chi.NewRouter() 86 87 // A good base middleware stack 88 r.Use(middleware.RequestID) 89 r.Use(middleware.RealIP) 90 r.Use(middleware.Logger) 91 r.Use(middleware.Recoverer) 92 93 // Set a timeout value on the request context (ctx), that will signal 94 // through ctx.Done() that the request has timed out and further 95 // processing should be stopped. 96 r.Use(middleware.Timeout(60 * time.Second)) 97 98 r.Get("/", func(w http.ResponseWriter, r *http.Request) { 99 w.Write([]byte("hi")) 100 }) 101 102 // RESTy routes for "articles" resource 103 r.Route("/articles", func(r chi.Router) { 104 r.With(paginate).Get("/", listArticles) // GET /articles 105 r.With(paginate).Get("/{month}-{day}-{year}", listArticlesByDate) // GET /articles/01-16-2017 106 107 r.Post("/", createArticle) // POST /articles 108 r.Get("/search", searchArticles) // GET /articles/search 109 110 // Regexp url parameters: 111 r.Get("/{articleSlug:[a-z-]+}", getArticleBySlug) // GET /articles/home-is-toronto 112 113 // Subrouters: 114 r.Route("/{articleID}", func(r chi.Router) { 115 r.Use(ArticleCtx) 116 r.Get("/", getArticle) // GET /articles/123 117 r.Put("/", updateArticle) // PUT /articles/123 118 r.Delete("/", deleteArticle) // DELETE /articles/123 119 }) 120 }) 121 122 // Mount the admin sub-router 123 r.Mount("/admin", adminRouter()) 124 125 http.ListenAndServe(":3333", r) 126 } 127 128 func ArticleCtx(next http.Handler) http.Handler { 129 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 130 articleID := chi.URLParam(r, "articleID") 131 article, err := dbGetArticle(articleID) 132 if err != nil { 133 http.Error(w, http.StatusText(404), 404) 134 return 135 } 136 ctx := context.WithValue(r.Context(), "article", article) 137 next.ServeHTTP(w, r.WithContext(ctx)) 138 }) 139 } 140 141 func getArticle(w http.ResponseWriter, r *http.Request) { 142 ctx := r.Context() 143 article, ok := ctx.Value("article").(*Article) 144 if !ok { 145 http.Error(w, http.StatusText(422), 422) 146 return 147 } 148 w.Write([]byte(fmt.Sprintf("title:%s", article.Title))) 149 } 150 151 // A completely separate router for administrator routes 152 func adminRouter() http.Handler { 153 r := chi.NewRouter() 154 r.Use(AdminOnly) 155 r.Get("/", adminIndex) 156 r.Get("/accounts", adminListAccounts) 157 return r 158 } 159 160 func AdminOnly(next http.Handler) http.Handler { 161 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 162 ctx := r.Context() 163 perm, ok := ctx.Value("acl.permission").(YourPermissionType) 164 if !ok || !perm.IsAdmin() { 165 http.Error(w, http.StatusText(403), 403) 166 return 167 } 168 next.ServeHTTP(w, r) 169 }) 170 } 171 ``` 172 173 174 ## Router design 175 176 chi's router is based on a kind of [Patricia Radix trie](https://en.wikipedia.org/wiki/Radix_tree). 177 The router is fully compatible with `net/http`. 178 179 Built on top of the tree is the `Router` interface: 180 181 ```go 182 // Router consisting of the core routing methods used by chi's Mux, 183 // using only the standard net/http. 184 type Router interface { 185 http.Handler 186 Routes 187 188 // Use appends one of more middlewares onto the Router stack. 189 Use(middlewares ...func(http.Handler) http.Handler) 190 191 // With adds inline middlewares for an endpoint handler. 192 With(middlewares ...func(http.Handler) http.Handler) Router 193 194 // Group adds a new inline-Router along the current routing 195 // path, with a fresh middleware stack for the inline-Router. 196 Group(fn func(r Router)) Router 197 198 // Route mounts a sub-Router along a `pattern`` string. 199 Route(pattern string, fn func(r Router)) Router 200 201 // Mount attaches another http.Handler along ./pattern/* 202 Mount(pattern string, h http.Handler) 203 204 // Handle and HandleFunc adds routes for `pattern` that matches 205 // all HTTP methods. 206 Handle(pattern string, h http.Handler) 207 HandleFunc(pattern string, h http.HandlerFunc) 208 209 // Method and MethodFunc adds routes for `pattern` that matches 210 // the `method` HTTP method. 211 Method(method, pattern string, h http.Handler) 212 MethodFunc(method, pattern string, h http.HandlerFunc) 213 214 // HTTP-method routing along `pattern` 215 Connect(pattern string, h http.HandlerFunc) 216 Delete(pattern string, h http.HandlerFunc) 217 Get(pattern string, h http.HandlerFunc) 218 Head(pattern string, h http.HandlerFunc) 219 Options(pattern string, h http.HandlerFunc) 220 Patch(pattern string, h http.HandlerFunc) 221 Post(pattern string, h http.HandlerFunc) 222 Put(pattern string, h http.HandlerFunc) 223 Trace(pattern string, h http.HandlerFunc) 224 225 // NotFound defines a handler to respond whenever a route could 226 // not be found. 227 NotFound(h http.HandlerFunc) 228 229 // MethodNotAllowed defines a handler to respond whenever a method is 230 // not allowed. 231 MethodNotAllowed(h http.HandlerFunc) 232 } 233 234 // Routes interface adds two methods for router traversal, which is also 235 // used by the github.com/go-chi/docgen package to generate documentation for Routers. 236 type Routes interface { 237 // Routes returns the routing tree in an easily traversable structure. 238 Routes() []Route 239 240 // Middlewares returns the list of middlewares in use by the router. 241 Middlewares() Middlewares 242 243 // Match searches the routing tree for a handler that matches 244 // the method/path - similar to routing a http request, but without 245 // executing the handler thereafter. 246 Match(rctx *Context, method, path string) bool 247 } 248 ``` 249 250 Each routing method accepts a URL `pattern` and chain of `handlers`. The URL pattern 251 supports named params (ie. `/users/{userID}`) and wildcards (ie. `/admin/*`). URL parameters 252 can be fetched at runtime by calling `chi.URLParam(r, "userID")` for named parameters 253 and `chi.URLParam(r, "*")` for a wildcard parameter. 254 255 256 ### Middleware handlers 257 258 chi's middlewares are just stdlib net/http middleware handlers. There is nothing special 259 about them, which means the router and all the tooling is designed to be compatible and 260 friendly with any middleware in the community. This offers much better extensibility and reuse 261 of packages and is at the heart of chi's purpose. 262 263 Here is an example of a standard net/http middleware handler using the new request context 264 available in Go 1.7+. This middleware sets a hypothetical user identifier on the request 265 context and calls the next handler in the chain. 266 267 ```go 268 // HTTP middleware setting a value on the request context 269 func MyMiddleware(next http.Handler) http.Handler { 270 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 271 ctx := context.WithValue(r.Context(), "user", "123") 272 next.ServeHTTP(w, r.WithContext(ctx)) 273 }) 274 } 275 ``` 276 277 278 ### Request handlers 279 280 chi uses standard net/http request handlers. This little snippet is an example of a http.Handler 281 func that reads a user identifier from the request context - hypothetically, identifying 282 the user sending an authenticated request, validated+set by a previous middleware handler. 283 284 ```go 285 // HTTP handler accessing data from the request context. 286 func MyRequestHandler(w http.ResponseWriter, r *http.Request) { 287 user := r.Context().Value("user").(string) 288 w.Write([]byte(fmt.Sprintf("hi %s", user))) 289 } 290 ``` 291 292 293 ### URL parameters 294 295 chi's router parses and stores URL parameters right onto the request context. Here is 296 an example of how to access URL params in your net/http handlers. And of course, middlewares 297 are able to access the same information. 298 299 ```go 300 // HTTP handler accessing the url routing parameters. 301 func MyRequestHandler(w http.ResponseWriter, r *http.Request) { 302 userID := chi.URLParam(r, "userID") // from a route like /users/{userID} 303 304 ctx := r.Context() 305 key := ctx.Value("key").(string) 306 307 w.Write([]byte(fmt.Sprintf("hi %v, %v", userID, key))) 308 } 309 ``` 310 311 312 ## Middlewares 313 314 chi comes equipped with an optional `middleware` package, providing a suite of standard 315 `net/http` middlewares. Please note, any middleware in the ecosystem that is also compatible 316 with `net/http` can be used with chi's mux. 317 318 ### Core middlewares 319 320 ----------------------------------------------------------------------------------------------------------- 321 | chi/middleware Handler | description | 322 |:----------------------|:--------------------------------------------------------------------------------- 323 | AllowContentType | Explicit whitelist of accepted request Content-Types | 324 | Compress | Gzip compression for clients that accept compressed responses | 325 | GetHead | Automatically route undefined HEAD requests to GET handlers | 326 | Heartbeat | Monitoring endpoint to check the servers pulse | 327 | Logger | Logs the start and end of each request with the elapsed processing time | 328 | NoCache | Sets response headers to prevent clients from caching | 329 | Profiler | Easily attach net/http/pprof to your routers | 330 | RealIP | Sets a http.Request's RemoteAddr to either X-Forwarded-For or X-Real-IP | 331 | Recoverer | Gracefully absorb panics and prints the stack trace | 332 | RequestID | Injects a request ID into the context of each request | 333 | RedirectSlashes | Redirect slashes on routing paths | 334 | SetHeader | Short-hand middleware to set a response header key/value | 335 | StripSlashes | Strip slashes on routing paths | 336 | Throttle | Puts a ceiling on the number of concurrent requests | 337 | Timeout | Signals to the request context when the timeout deadline is reached | 338 | URLFormat | Parse extension from url and put it on request context | 339 | WithValue | Short-hand middleware to set a key/value on the request context | 340 ----------------------------------------------------------------------------------------------------------- 341 342 ### Auxiliary middlewares & packages 343 344 Please see https://github.com/go-chi for additional packages. 345 346 -------------------------------------------------------------------------------------------------------------------- 347 | package | description | 348 |:---------------------------------------------------|:------------------------------------------------------------- 349 | [cors](https://github.com/go-chi/cors) | Cross-origin resource sharing (CORS) | 350 | [jwtauth](https://github.com/go-chi/jwtauth) | JWT authentication | 351 | [hostrouter](https://github.com/go-chi/hostrouter) | Domain/host based request routing | 352 | [httpcoala](https://github.com/go-chi/httpcoala) | HTTP request coalescer | 353 | [chi-authz](https://github.com/casbin/chi-authz) | Request ACL via https://github.com/hsluoyz/casbin | 354 | [phi](https://github.com/fate-lovely/phi) | Port chi to [fasthttp](https://github.com/valyala/fasthttp) | 355 -------------------------------------------------------------------------------------------------------------------- 356 357 please [submit a PR](./CONTRIBUTING.md) if you'd like to include a link to a chi-compatible middleware 358 359 360 ## context? 361 362 `context` is a tiny pkg that provides simple interface to signal context across call stacks 363 and goroutines. It was originally written by [Sameer Ajmani](https://github.com/Sajmani) 364 and is available in stdlib since go1.7. 365 366 Learn more at https://blog.golang.org/context 367 368 and.. 369 * Docs: https://golang.org/pkg/context 370 * Source: https://github.com/golang/go/tree/master/src/context 371 372 373 ## Benchmarks 374 375 The benchmark suite: https://github.com/pkieltyka/go-http-routing-benchmark 376 377 Results as of Aug 31, 2017 on Go 1.9.0 378 379 ```shell 380 BenchmarkChi_Param 3000000 607 ns/op 432 B/op 3 allocs/op 381 BenchmarkChi_Param5 2000000 935 ns/op 432 B/op 3 allocs/op 382 BenchmarkChi_Param20 1000000 1944 ns/op 432 B/op 3 allocs/op 383 BenchmarkChi_ParamWrite 2000000 664 ns/op 432 B/op 3 allocs/op 384 BenchmarkChi_GithubStatic 2000000 627 ns/op 432 B/op 3 allocs/op 385 BenchmarkChi_GithubParam 2000000 847 ns/op 432 B/op 3 allocs/op 386 BenchmarkChi_GithubAll 10000 175556 ns/op 87700 B/op 609 allocs/op 387 BenchmarkChi_GPlusStatic 3000000 566 ns/op 432 B/op 3 allocs/op 388 BenchmarkChi_GPlusParam 2000000 652 ns/op 432 B/op 3 allocs/op 389 BenchmarkChi_GPlus2Params 2000000 767 ns/op 432 B/op 3 allocs/op 390 BenchmarkChi_GPlusAll 200000 9794 ns/op 5616 B/op 39 allocs/op 391 BenchmarkChi_ParseStatic 3000000 590 ns/op 432 B/op 3 allocs/op 392 BenchmarkChi_ParseParam 2000000 656 ns/op 432 B/op 3 allocs/op 393 BenchmarkChi_Parse2Params 2000000 715 ns/op 432 B/op 3 allocs/op 394 BenchmarkChi_ParseAll 100000 18045 ns/op 11232 B/op 78 allocs/op 395 BenchmarkChi_StaticAll 10000 108871 ns/op 67827 B/op 471 allocs/op 396 ``` 397 398 Comparison with other routers: https://gist.github.com/pkieltyka/c089f309abeb179cfc4deaa519956d8c 399 400 NOTE: the allocs in the benchmark above are from the calls to http.Request's 401 `WithContext(context.Context)` method that clones the http.Request, sets the `Context()` 402 on the duplicated (alloc'd) request and returns it the new request object. This is just 403 how setting context on a request in Go 1.7+ works. 404 405 406 ## Credits 407 408 * Carl Jackson for https://github.com/zenazn/goji 409 * Parts of chi's thinking comes from goji, and chi's middleware package 410 sources from goji. 411 * Armon Dadgar for https://github.com/armon/go-radix 412 * Contributions: [@VojtechVitek](https://github.com/VojtechVitek) 413 414 We'll be more than happy to see [your contributions](./CONTRIBUTING.md)! 415 416 417 ## Beyond REST 418 419 chi is just a http router that lets you decompose request handling into many smaller layers. 420 Many companies including Pressly.com (of course) use chi to write REST services for their public 421 APIs. But, REST is just a convention for managing state via HTTP, and there's a lot of other pieces 422 required to write a complete client-server system or network of microservices. 423 424 Looking ahead beyond REST, I also recommend some newer works in the field coming from 425 [gRPC](https://github.com/grpc/grpc-go), [NATS](https://nats.io), [go-kit](https://github.com/go-kit/kit) 426 and even [graphql](https://github.com/graphql-go/graphql). They're all pretty cool with their 427 own unique approaches and benefits. Specifically, I'd look at gRPC since it makes client-server 428 communication feel like a single program on a single computer, no need to hand-write a client library 429 and the request/response payloads are typed contracts. NATS is pretty amazing too as a super 430 fast and lightweight pub-sub transport that can speak protobufs, with nice service discovery - 431 an excellent combination with gRPC. 432 433 434 ## License 435 436 Copyright (c) 2015-present [Peter Kieltyka](https://github.com/pkieltyka) 437 438 Licensed under [MIT License](./LICENSE) 439 440 [GoDoc]: https://godoc.org/github.com/go-chi/chi 441 [GoDoc Widget]: https://godoc.org/github.com/go-chi/chi?status.svg 442 [Travis]: https://travis-ci.org/go-chi/chi 443 [Travis Widget]: https://travis-ci.org/go-chi/chi.svg?branch=master