lightweight, idiomatic and composable router for building Go HTTP services

Overview

chi

GoDoc Widget Travis Widget

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 that are kept maintainable as your project grows and changes. chi is built on the new context package introduced in Go 1.7 to handle signaling, cancelation and request-scoped values across a handler chain.

The focus of the project has been to seek out an elegant and comfortable design for writing REST API servers, written during the development of the Pressly API service that powers our public API service, which in turn powers all of our client-side applications.

The key considerations of chi's design are: project structure, maintainability, standard http handlers (stdlib-only), developer productivity, and deconstructing a large system into many small parts. The core router github.com/go-chi/chi is quite small (less than 1000 LOC), but we've also included some useful/optional subpackages: middleware, render and docgen. We hope you enjoy it too!

Install

go get -u github.com/go-chi/chi/v5

Features

  • Lightweight - cloc'd in ~1000 LOC for the chi router
  • Fast - yes, see benchmarks
  • 100% compatible with net/http - use any http or middleware pkg in the ecosystem that is also compatible with net/http
  • Designed for modular/composable APIs - middlewares, inline middlewares, route groups and sub-router mounting
  • Context control - built on new context package, providing value chaining, cancellations and timeouts
  • Robust - in production at Pressly, CloudFlare, Heroku, 99Designs, and many others (see discussion)
  • Doc generation - docgen auto-generates routing documentation from your source to JSON or Markdown
  • Go.mod support - v1.x of chi (starting from v1.5.0), now has go.mod support (see CHANGELOG)
  • No external dependencies - plain ol' Go stdlib + net/http

Examples

See _examples/ for a variety of examples.

As easy as:

package main

import (
	"net/http"

	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
)

func main() {
	r := chi.NewRouter()
	r.Use(middleware.Logger)
	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("welcome"))
	})
	http.ListenAndServe(":3000", r)
}

REST Preview:

Here is a little preview of how routing looks like with chi. Also take a look at the generated routing docs in JSON (routes.json) and in Markdown (routes.md).

I highly recommend reading the source of the examples listed above, they will show you all the features of chi and serve as a good form of documentation.

import (
  //...
  "context"
  "github.com/go-chi/chi/v5"
  "github.com/go-chi/chi/v5/middleware"
)

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

  // A good base middleware stack
  r.Use(middleware.RequestID)
  r.Use(middleware.RealIP)
  r.Use(middleware.Logger)
  r.Use(middleware.Recoverer)

  // Set a timeout value on the request context (ctx), that will signal
  // through ctx.Done() that the request has timed out and further
  // processing should be stopped.
  r.Use(middleware.Timeout(60 * time.Second))

  r.Get("/", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hi"))
  })

  // RESTy routes for "articles" resource
  r.Route("/articles", func(r chi.Router) {
    r.With(paginate).Get("/", listArticles)                           // GET /articles
    r.With(paginate).Get("/{month}-{day}-{year}", listArticlesByDate) // GET /articles/01-16-2017

    r.Post("/", createArticle)                                        // POST /articles
    r.Get("/search", searchArticles)                                  // GET /articles/search

    // Regexp url parameters:
    r.Get("/{articleSlug:[a-z-]+}", getArticleBySlug)                // GET /articles/home-is-toronto

    // Subrouters:
    r.Route("/{articleID}", func(r chi.Router) {
      r.Use(ArticleCtx)
      r.Get("/", getArticle)                                          // GET /articles/123
      r.Put("/", updateArticle)                                       // PUT /articles/123
      r.Delete("/", deleteArticle)                                    // DELETE /articles/123
    })
  })

  // Mount the admin sub-router
  r.Mount("/admin", adminRouter())

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

func ArticleCtx(next http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    articleID := chi.URLParam(r, "articleID")
    article, err := dbGetArticle(articleID)
    if err != nil {
      http.Error(w, http.StatusText(404), 404)
      return
    }
    ctx := context.WithValue(r.Context(), "article", article)
    next.ServeHTTP(w, r.WithContext(ctx))
  })
}

func getArticle(w http.ResponseWriter, r *http.Request) {
  ctx := r.Context()
  article, ok := ctx.Value("article").(*Article)
  if !ok {
    http.Error(w, http.StatusText(422), 422)
    return
  }
  w.Write([]byte(fmt.Sprintf("title:%s", article.Title)))
}

// A completely separate router for administrator routes
func adminRouter() http.Handler {
  r := chi.NewRouter()
  r.Use(AdminOnly)
  r.Get("/", adminIndex)
  r.Get("/accounts", adminListAccounts)
  return r
}

func AdminOnly(next http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()
    perm, ok := ctx.Value("acl.permission").(YourPermissionType)
    if !ok || !perm.IsAdmin() {
      http.Error(w, http.StatusText(403), 403)
      return
    }
    next.ServeHTTP(w, r)
  })
}

Router interface

chi's router is based on a kind of Patricia Radix trie. The router is fully compatible with net/http.

Built on top of the tree is the Router interface:

// Router consisting of the core routing methods used by chi's Mux,
// using only the standard net/http.
type Router interface {
	http.Handler
	Routes

	// Use appends one or more middlewares onto the Router stack.
	Use(middlewares ...func(http.Handler) http.Handler)

	// With adds inline middlewares for an endpoint handler.
	With(middlewares ...func(http.Handler) http.Handler) Router

	// Group adds a new inline-Router along the current routing
	// path, with a fresh middleware stack for the inline-Router.
	Group(fn func(r Router)) Router

	// Route mounts a sub-Router along a `pattern`` string.
	Route(pattern string, fn func(r Router)) Router

	// Mount attaches another http.Handler along ./pattern/*
	Mount(pattern string, h http.Handler)

	// Handle and HandleFunc adds routes for `pattern` that matches
	// all HTTP methods.
	Handle(pattern string, h http.Handler)
	HandleFunc(pattern string, h http.HandlerFunc)

	// Method and MethodFunc adds routes for `pattern` that matches
	// the `method` HTTP method.
	Method(method, pattern string, h http.Handler)
	MethodFunc(method, pattern string, h http.HandlerFunc)

	// HTTP-method routing along `pattern`
	Connect(pattern string, h http.HandlerFunc)
	Delete(pattern string, h http.HandlerFunc)
	Get(pattern string, h http.HandlerFunc)
	Head(pattern string, h http.HandlerFunc)
	Options(pattern string, h http.HandlerFunc)
	Patch(pattern string, h http.HandlerFunc)
	Post(pattern string, h http.HandlerFunc)
	Put(pattern string, h http.HandlerFunc)
	Trace(pattern string, h http.HandlerFunc)

	// NotFound defines a handler to respond whenever a route could
	// not be found.
	NotFound(h http.HandlerFunc)

	// MethodNotAllowed defines a handler to respond whenever a method is
	// not allowed.
	MethodNotAllowed(h http.HandlerFunc)
}

// Routes interface adds two methods for router traversal, which is also
// used by the github.com/go-chi/docgen package to generate documentation for Routers.
type Routes interface {
	// Routes returns the routing tree in an easily traversable structure.
	Routes() []Route

	// Middlewares returns the list of middlewares in use by the router.
	Middlewares() Middlewares

	// Match searches the routing tree for a handler that matches
	// the method/path - similar to routing a http request, but without
	// executing the handler thereafter.
	Match(rctx *Context, method, path string) bool
}

Each routing method accepts a URL pattern and chain of handlers. The URL pattern supports named params (ie. /users/{userID}) and wildcards (ie. /admin/*). URL parameters can be fetched at runtime by calling chi.URLParam(r, "userID") for named parameters and chi.URLParam(r, "*") for a wildcard parameter.

Middleware handlers

chi's middlewares are just stdlib net/http middleware handlers. There is nothing special about them, which means the router and all the tooling is designed to be compatible and friendly with any middleware in the community. This offers much better extensibility and reuse of packages and is at the heart of chi's purpose.

Here is an example of a standard net/http middleware where we assign a context key "user" the value of "123". This middleware sets a hypothetical user identifier on the request context and calls the next handler in the chain.

// HTTP middleware setting a value on the request context
func MyMiddleware(next http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    // create new context from `r` request context, and assign key `"user"`
    // to value of `"123"`
    ctx := context.WithValue(r.Context(), "user", "123")

    // call the next handler in the chain, passing the response writer and
    // the updated request object with the new context value.
    //
    // note: context.Context values are nested, so any previously set
    // values will be accessible as well, and the new `"user"` key
    // will be accessible from this point forward.
    next.ServeHTTP(w, r.WithContext(ctx))
  })
}

Request handlers

chi uses standard net/http request handlers. This little snippet is an example of a http.Handler func that reads a user identifier from the request context - hypothetically, identifying the user sending an authenticated request, validated+set by a previous middleware handler.

// HTTP handler accessing data from the request context.
func MyRequestHandler(w http.ResponseWriter, r *http.Request) {
  // here we read from the request context and fetch out `"user"` key set in
  // the MyMiddleware example above.
  user := r.Context().Value("user").(string)

  // respond to the client
  w.Write([]byte(fmt.Sprintf("hi %s", user)))
}

URL parameters

chi's router parses and stores URL parameters right onto the request context. Here is an example of how to access URL params in your net/http handlers. And of course, middlewares are able to access the same information.

// HTTP handler accessing the url routing parameters.
func MyRequestHandler(w http.ResponseWriter, r *http.Request) {
  // fetch the url parameter `"userID"` from the request of a matching
  // routing pattern. An example routing pattern could be: /users/{userID}
  userID := chi.URLParam(r, "userID")

  // fetch `"key"` from the request context
  ctx := r.Context()
  key := ctx.Value("key").(string)

  // respond to the client
  w.Write([]byte(fmt.Sprintf("hi %v, %v", userID, key)))
}

Middlewares

chi comes equipped with an optional middleware package, providing a suite of standard net/http middlewares. Please note, any middleware in the ecosystem that is also compatible with net/http can be used with chi's mux.

Core middlewares


chi/middleware Handler description
AllowContentEncoding Enforces a whitelist of request Content-Encoding headers
AllowContentType Explicit whitelist of accepted request Content-Types
BasicAuth Basic HTTP authentication
Compress Gzip compression for clients that accept compressed responses
ContentCharset Ensure charset for Content-Type request headers
CleanPath Clean double slashes from request path
GetHead Automatically route undefined HEAD requests to GET handlers
Heartbeat Monitoring endpoint to check the servers pulse
Logger Logs the start and end of each request with the elapsed processing time
NoCache Sets response headers to prevent clients from caching
Profiler Easily attach net/http/pprof to your routers
RealIP Sets a http.Request's RemoteAddr to either X-Forwarded-For or X-Real-IP
Recoverer Gracefully absorb panics and prints the stack trace
RequestID Injects a request ID into the context of each request
RedirectSlashes Redirect slashes on routing paths
RouteHeaders Route handling for request headers
SetHeader Short-hand middleware to set a response header key/value
StripSlashes Strip slashes on routing paths
Throttle Puts a ceiling on the number of concurrent requests
Timeout Signals to the request context when the timeout deadline is reached
URLFormat Parse extension from url and put it on request context
WithValue Short-hand middleware to set a key/value on the request context

Extra middlewares & packages

Please see https://github.com/go-chi for additional packages.


package description
cors Cross-origin resource sharing (CORS)
docgen Print chi.Router routes at runtime
jwtauth JWT authentication
hostrouter Domain/host based request routing
httplog Small but powerful structured HTTP request logging
httprate HTTP request rate limiter
httptracer HTTP request performance tracing library
httpvcr Write deterministic tests for external sources
stampede HTTP request coalescer

context?

context is a tiny pkg that provides simple interface to signal context across call stacks and goroutines. It was originally written by Sameer Ajmani and is available in stdlib since go1.7.

Learn more at https://blog.golang.org/context

and..

Benchmarks

The benchmark suite: https://github.com/pkieltyka/go-http-routing-benchmark

Results as of Nov 29, 2020 with Go 1.15.5 on Linux AMD 3950x

BenchmarkChi_Param          	3075895	        384 ns/op	      400 B/op      2 allocs/op
BenchmarkChi_Param5         	2116603	        566 ns/op	      400 B/op      2 allocs/op
BenchmarkChi_Param20        	 964117	       1227 ns/op	      400 B/op      2 allocs/op
BenchmarkChi_ParamWrite     	2863413	        420 ns/op	      400 B/op      2 allocs/op
BenchmarkChi_GithubStatic   	3045488	        395 ns/op	      400 B/op      2 allocs/op
BenchmarkChi_GithubParam    	2204115	        540 ns/op	      400 B/op      2 allocs/op
BenchmarkChi_GithubAll      	  10000	     113811 ns/op	    81203 B/op    406 allocs/op
BenchmarkChi_GPlusStatic    	3337485	        359 ns/op	      400 B/op      2 allocs/op
BenchmarkChi_GPlusParam     	2825853	        423 ns/op	      400 B/op      2 allocs/op
BenchmarkChi_GPlus2Params   	2471697	        483 ns/op	      400 B/op      2 allocs/op
BenchmarkChi_GPlusAll       	 194220	       5950 ns/op	     5200 B/op     26 allocs/op
BenchmarkChi_ParseStatic    	3365324	        356 ns/op	      400 B/op      2 allocs/op
BenchmarkChi_ParseParam     	2976614	        404 ns/op	      400 B/op      2 allocs/op
BenchmarkChi_Parse2Params   	2638084	        439 ns/op	      400 B/op      2 allocs/op
BenchmarkChi_ParseAll       	 109567	      11295 ns/op	    10400 B/op     52 allocs/op
BenchmarkChi_StaticAll      	  16846	      71308 ns/op	    62802 B/op    314 allocs/op

Comparison with other routers: https://gist.github.com/pkieltyka/123032f12052520aaccab752bd3e78cc

NOTE: the allocs in the benchmark above are from the calls to http.Request's WithContext(context.Context) method that clones the http.Request, sets the Context() on the duplicated (alloc'd) request and returns it the new request object. This is just how setting context on a request in Go works.

Go module support & note on chi's versioning

  • Go.mod support means we reset our versioning starting from v1.5 (see CHANGELOG)
  • All older tags are preserved, are backwards-compatible and will "just work" as they
  • Brand new systems can run go get -u github.com/go-chi/chi as normal, or go get -u github.com/go-chi/chi@latest to install chi, which will install v1.x+ built with go.mod support, starting from v1.5.0.
  • For existing projects who want to upgrade to the latest go.mod version, run: go get -u github.com/go-chi/[email protected], which will get you on the go.mod version line (as Go's mod cache may still remember v4.x).
  • Any breaking changes will bump a "minor" release and backwards-compatible improvements/fixes will bump a "tiny" release.

Credits

We'll be more than happy to see your contributions!

Beyond REST

chi is just a http router that lets you decompose request handling into many smaller layers. Many companies use chi to write REST services for their public APIs. But, REST is just a convention for managing state via HTTP, and there's a lot of other pieces required to write a complete client-server system or network of microservices.

Looking beyond REST, I also recommend some newer works in the field:

  • webrpc - Web-focused RPC client+server framework with code-gen
  • gRPC - Google's RPC framework via protobufs
  • graphql - Declarative query language
  • NATS - lightweight pub-sub

License

Copyright (c) 2015-present Peter Kieltyka

Licensed under MIT License

Comments
  • chi@v1.5.x mod issues

    [email protected] mod issues

    I have tried to switch to v1.5.0 from v4.1.2+incompatible but because the version number decreased it caused a downgrade of all other dependencies using chi. For example, I have started with this:

    git.example.com/commons/pkg/rest v1.3.2
    github.com/go-chi/chi v4.1.2+incompatible
    github.com/go-chi/render v1.0.1
    

    After running go get github.com/go-chi/[email protected] I got:

    git.example.com/commons/pkg/rest v1.1.0
    github.com/go-chi/chi v1.5.1
    github.com/go-chi/render v1.0.1
    

    As you can see my pkg/rest downgraded to some old version and such side effects can be very unexpected and unpleasant.

    Is there a reason why you decided to go with v1.5.x and not with a more traditional (and less dangerous) approach with v5 (also changing the package name to "/v5")? I'm not sure how to deal with this. In order to avoid those unexpected downgrades I have to have all of my dependencies migrated to v1.5, but unfortunately some of them not under my control.

    opened by umputun 76
  • HEAD for GET routes

    HEAD for GET routes

    Standard go http router allows to do HEAD requests to GET endpoints and return the same response but without body. Chi response 405 for GET routes with HEAD method.

    opened by alehano 58
  • Add go.mod file

    Add go.mod file

    Perhaps you've been following the discussion around the future of go dependency management? https://research.swtch.com/vgo

    Anyways, a few unrelated people, including me have tried to play with this experiment in our own projects and we are running into problems import chi due to it not having a go.mod file properly advertising the major version as v3.

    Any chance chi could partake in this experiment?

    I'm willing to give creating a proper chi go.mod file a go in a PR if so.

    opened by nicpottier 38
  • Render: managing request and response payload as types

    Render: managing request and response payload as types

    The render subpkg is pretty cool, and its great for managing the different kinds of content types a response may need, including streams. However, one of the important parts for a maintainable API is to manage the request and response payloads (the inputs and the outputs of an endpoint).

    For request payloads, one simple idea is to have a Bind() middleware used in chi's r.With() inline middleware routing, that will take a request body and unmarshal it to a kind of struct. Perhaps.

    type ArticleRequest {
      ID int64 `json:"id"`
      Name string `json:"name"`
    }
    // ...
    r.Get("/", index)
    r.With(render.Request(&ArticleRequest{})).Post("/articles", newArticle)
    

    .. something like that.. the render.Request() would make a new &ArticleRequest{} object and put it on the context under render.RequestKey or something.. its a decent plan, except it would require some kind of reflection to make the new &ArticleRequest{} object.

    As for response payloads, that should be much simpler, just..

    type ArticleResponse {
      *data.Article // embed the core Article type
      // add more methods on it..
    }
    //...
    render.Respond(w, r, &ArticleResponse{a})
    

    if someone has other ideas too that would be awesome!

    opened by pkieltyka 23
  • Question: HTTP Status Code

    Question: HTTP Status Code

    How do you set the HTTP Status code to something other than 200? I have a simple test case below and I'm unable to change the HTTP Status code. It is always a 200 OK. I can render my own text(JSON) but this still does NOT set the HTTP Status code to 401!

    package main
    func routes() *chi.Mux {
    	router := chi.NewRouter()
    	router.Use(
    		render.SetContentType(render.ContentTypeJSON),
    		middleware.Logger,
    		middleware.DefaultCompress,
    		middleware.RedirectSlashes,
    		middleware.Recoverer,
    		middleware.RealIP,
    	)
    	router.Get("/test", test)
    	return router
    }
    
    func test(w http.ResponseWriter, r *http.Request) {
    	w.WriteHeader(401)
    	http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
    	render.Status(r, 401)
    	render.Render(w, r, ErrInvalidRequest())
    	return
    }
    type ErrResponse struct {
    	Err            error `json:"-"` // low-level runtime error
    	HTTPStatusCode int   `json:"-"` // http response status code
    
    	StatusText string `json:"status"`          // user-level status message
    	AppCode    int64  `json:"code,omitempty"`  // application-specific error code
    	ErrorText  string `json:"error,omitempty"` // application-level error message, for debugging
    }
    
    func (e *ErrResponse) Render(w http.ResponseWriter, r *http.Request) error {
    	render.Status(r, e.HTTPStatusCode)
    	return nil
    }
    
    func ErrInvalidRequest() render.Renderer {
    	return &ErrResponse{
    		// Err:            err,
    		HTTPStatusCode: 401,
    		StatusText:     "Invalid request.",
    		ErrorText:      "Invalid request.",
    	}
    }
    func main() {
    	router := routes()
    
    	walkFunc := func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error {
    		log.Printf("%s %s\n", method, route)
    		return nil
    	}
    	if err := chi.Walk(router, walkFunc); err != nil {
    		log.Panicf("Loggin err: %s\n", err.Error())
    	}
    	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", cfg.SrvPort), router))
    }
    

    Results - The text is changed but NOT the HTTP status code

    curl --request GET  --url http://localhost:8080/test -i
    HTTP/1.1 200 OK
    Content-Type: text/plain; charset=utf-8
    X-Content-Type-Options: nosniff
    Date: Tue, 19 Feb 2019 16:56:46 GMT
    Content-Length: 57
    
    Unauthorized
    {"status":401,"message":"Invalid request."}
    
    opened by milesje 18
  • Route params mixup

    Route params mixup

    First of all, love the project & the philosophy behind it - it's the perfect approach for Go 1.7+ IMO :thumbsup:

    But I'm having an issue with some supporting some legacy route formats. Requests map to the correct handlers but the parameters don't match up correctly. Here's a simplified example replacing the routes in TestTree to show the issue I'm having:

    func TestTree(t *testing.T) {
        hDate := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
        hCat := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
    
        tr := &node{}
    
        tr.InsertRoute(mGET, "/items/:year/:month", hDate)
        tr.InsertRoute(mGET, "/items/:category", hCat)
    
        tests := []struct {
            r string            // input request path
            h http.Handler      // output matched handler
            p map[string]string // output params
        }{
            {r: "/items/2016/08", h: hDate, p: map[string]string{"year": "2016", "month": "08"}},
            {r: "/items/things", h: hCat, p: map[string]string{"category": "things"}},
        }
    

    That results in:

    --- FAIL: TestTree (0.00s)
        tree_test.go:59: input [1]: find '/items/things' expecting params:map[category:things] , got:map[year:things]
    

    Note that the /items/:category handler is correctly used but the parameter is called :year instead from the previous route.

    It looks like it's due to how the tree is built with the name of the parameter ignored so it then gets the name from the previous node:

    2016/08/23 10:40:56 [node 0 parent:0] typ:0 prefix: label: numEdges:1 isLeaf:false
    2016/08/23 10:40:56 [node 1 parent:0] typ:0 prefix:/items/ label:/ numEdges:1 isLeaf:false
    2016/08/23 10:40:56 [node 2 parent:1] typ:2 prefix::year label:: numEdges:1 isLeaf:true handler:map[512:<nil> 4:0x90450]
    2016/08/23 10:40:56 [node 3 parent:2] typ:0 prefix:/ label:/ numEdges:1 isLeaf:false
    2016/08/23 10:40:56 [node 4 parent:3] typ:2 prefix::month label:: numEdges:0 isLeaf:true handler:map[512:<nil> 4:0x90440]
    

    Is this simply not supported (I know many Go routers are strict about the route variations, others such as Echo cope better with suffix variations) or is it a bug?

    Many thanks.

    opened by CaptainCodeman 18
  • chi v3 roadmap

    chi v3 roadmap

    • [x] Fix bugs #78 #100 - relating to param keys overlapping between different endpoints
    • [x] Change param syntax from /articles/:id to /articles/{id} which improves expressiveness and delimiting (#167)
    • [x] Add support for regexp via /articles/{name:[a-z]}
    • [x] Add support for http.Handler for method routing, as in #176
    • [ ] Add a few param helpers with as chi.URLParamInt64(r, "bookID")
    • [x] Solve: Subrouters stacked, both using /{id} param key - panic? - #61
    opened by pkieltyka 15
  • Feature Request: Add URL param/query helpers

    Feature Request: Add URL param/query helpers

    In Chi, there is a helper to get the URL param. It has this signature:

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

    I found I would often have to import strconv and convert a number param to an int. So I forked and created a method with a signature like so:

    func ParamInt(r *http.Request, key string) (int, error)
    

    Then I came across an issue with query parameters. I want to get a query parameter by name without having to parse it manually on each endpoint, and they also might be numbers that should be converted to ints.

    So I created these two signatures as well:

    func QueryString(r *http.Request, key string) string
    func QueryStringInt(r *http.Request, key string) (int, error)
    

    Here is the logic for everything:

    context.go:

    // Param returns the url parameter from a http.Request object.
    func Param(r *http.Request, key string) string {
    	if rctx := RouteContext(r.Context()); rctx != nil {
    		return rctx.Param(key)
    	}
    	return ""
    }
    
    // ParamInt will get a param from the request URL and attempt to parse it as an int.
    func ParamInt(r *http.Request, key string) (int, error) {
    	val, err := strconv.Atoi(Param(r, key))
    	if err != nil {
    		return 0, err
    	}
    	return val, nil
    }
    
    // Query will get a query parameter by key.
    func QueryString(r *http.Request, key string) string {
    	if rctx := RouteContext(r.Context()); rctx != nil {
    		return rctx.QueryString(key)
    	}
    	return ""
    }
    
    // QueryInt will get a query parameter by key and convert it to an int or return an error.
    func QueryStringInt(r *http.Request, key string) (int, error) {
    	val, err := strconv.Atoi(QueryString(r, key))
    	if err != nil {
    		return 0, err
    	}
    	return val, nil
    }
    

    Would you be willing to implement this so I don't need to use a forked version? :P

    opened by lansana 14
  • http: multiple response.WriteHeader calls due CloseNotify

    http: multiple response.WriteHeader calls due CloseNotify

    Adding CloseNotify middleware causing sometimes "multiple response.WriteHeader calls" warning in normal cases, i.e. request was not canceled by caller, but finished normally.

    Probably sometimes https://github.com/pressly/chi/blob/master/middleware/closenotify.go#L32 reached after normal completion? Not sure what the sequence, but I suspect client completed (and disconnected), connection closed and in select it gets closeNotifyCh

    opened by umputun 14
  • Wildcard

    Wildcard "*" behaves unexpectedly when used in conjunction with a nested router which has url parameters.

    Given:

    	r := chi.NewRouter()
    
    	r.Get("/bare/{param}", testStar)
    	r.Get("/bare/{param}/*", testStar)
    
    	r.Route("/case0", func(r chi.Router) {
    		r.Get("/{param}", testStar) // (1)
    		r.Get("/{param}/*", testStar) // (2)
    	})
    

    In case (1) wildcard "*" evaluates to browse/<path_segment> given url <path>/browse/<path_segment> In case (2) wildcard "*" evaluates to <sub_path_1>/<sub_path_2> given url <path>/browse/<path_segment>/<sub_path_1>/<sub_path_2>

    UPDATE: (Minimum reproducible example)

    package main
    
    import (
    	"fmt"
    	"io/ioutil"
    	"net/http"
    
    	"github.com/go-chi/chi"
    )
    
    func main() {
    	r := chi.NewRouter()
    
    	r.Get("/bare/{param}", testStar)
    	r.Get("/bare/{param}/*", testStar)
    
    	{ // case 0: Mounting a router using callback.
    		r.Route("/case0", func(r chi.Router) {
    			r.Get("/{param}", testStar)
    			r.Get("/{param}/*", testStar)
    		})
    	}
    	{ // case 1: Explicitly mounting a router.
    		sr := chi.NewRouter()
    		sr.Get("/{param}", testStar)
    		sr.Get("/{param}/*", testStar)
    		r.Mount("/case1", sr)
    	}
    
    	go http.ListenAndServe(":8080", r)
    
    	testCases := []struct {
    		url    string
    		params map[string]string
    	}{
    		{url: "value", params: map[string]string{
    			"param": "value",
    			"*":     "",
    		}},
    		{url: "value/sub/path", params: map[string]string{
    			"param": "value",
    			"*":     "sub/path",
    		}},
    	}
    
    	prefixes := []string{
    		"bare",
    		"case0",
    		"case1",
    	}
    
    	for _, prefix := range prefixes {
    		for _, tc := range testCases {
    			url := fmt.Sprintf("http://localhost:8080/%v/%v", prefix, tc.url)
    			printHttp(url, tc.params)
    		}
    	}
    }
    
    func testStar(rw http.ResponseWriter, r *http.Request) {
    	ctx := chi.RouteContext(r.Context())
    	fmt.Fprintf(rw, "pattern: %v\n", ctx.RoutePattern())
    	fmt.Fprintf(rw, "  param: (%v) *: (%v)", ctx.URLParam("param"), ctx.URLParam("*"))
    }
    
    func printHttp(url string, params map[string]string) {
    	r, err := http.Get(url)
    	if err != nil {
    		fmt.Println("url:", url, "\n\terr:", err)
    	}
    	data, _ := ioutil.ReadAll(r.Body)
    
    	fmt.Println("url:", url)
    
    	fmt.Println("--   ACTUAL:")
    	fmt.Println(string(data))
    
    	fmt.Println("-- EXPECTED:")
    	fmt.Printf("  param: (%v) *: (%v)", params["param"], params["*"])
    
    	fmt.Printf("\n\n")
    }
    

    Output:

    url: http://localhost:8080/bare/value
    --   ACTUAL:
    pattern: /bare/{param}
      param: (value) *: ()
    -- EXPECTED:
      param: (value) *: ()
    
    url: http://localhost:8080/bare/value/sub/path
    --   ACTUAL:
    pattern: /bare/{param}/*
      param: (value) *: (sub/path)
    -- EXPECTED:
      param: (value) *: (sub/path)
    
    url: http://localhost:8080/case0/value
    --   ACTUAL:
    pattern: /case0/{param}
      param: (value) *: (value)
    -- EXPECTED:
      param: (value) *: ()
    
    url: http://localhost:8080/case0/value/sub/path
    --   ACTUAL:
    pattern: /case0/{param}/*
      param: (value) *: (sub/path)
    -- EXPECTED:
      param: (value) *: (sub/path)
    
    url: http://localhost:8080/case1/value
    --   ACTUAL:
    pattern: /case1/{param}
      param: (value) *: (value)
    -- EXPECTED:
      param: (value) *: ()
    
    url: http://localhost:8080/case1/value/sub/path
    --   ACTUAL:
    pattern: /case1/{param}/*
      param: (value) *: (sub/path)
    -- EXPECTED:
      param: (value) *: (sub/path)
    
    opened by NonLogicalDev 13
  • chi v4

    chi v4

    chi is a pretty minimal library and has been hardened over the years, so v4 won't introduce any big changes other then a few minor things like..

    • [x] chi's Go support will be inline with Go's own support - #366 - therefore, we remove support for Go 1.7 and 1.8, and stop tracking 1.9
    • [x] return 404 for mux with empty routes #362
    • [x] additional check to ensure wildcard is at the end of a url pattern #333
    • [x] middleware: deprecate support for CloseNotifier - #347
    • [ ] Optimal Go module handling #302 - some community submissions: #364 #370 #379

    :)

    opened by pkieltyka 13
  • Exclude certain routes or patterns from logger middleware

    Exclude certain routes or patterns from logger middleware

    It's pretty common to want some routes not included in the logging, an obvious example is a health check when being used by a load balancer or other probe, or a Prometheus metrics endpoint - generates thousands of lines unnecessary output & logging. In addition there might be certain patterns like email address which accidentally get logged and leak PII

    I wanted to use the logging middleware but also exclude some routes, however I can find no way to do this without providing my own full implementation of the LogFormatter interface.

    Ideally an array of RegEx patterns could be configured for logging exclusion, which are applied to the URI of the requests

    opened by benc-uk 1
  • middleware: SetAllowHeader adds the Allow header on 405 response

    middleware: SetAllowHeader adds the Allow header on 405 response

    By adding the Allow header with the lists of available methods on 405 Method Not Found error, this PR makes chi compliant with rfc9110, because this behaviour is not currently supported in Chi.

    Note that it also make chi look better on this article (that will need to be updated). This article is the first to appear when searching on google "golang choose router".

    It adds a small but non-negligable performance offset, that's why it is proposed as a middleware

    Closes #446.

    Don't hesitate to ask for changes. Thanks for this amazing package :)


    Performance details

    BenchmarkSetAllowHeaderWhen405-8         1509776               776.7 ns/op           483 B/op          2 allocs/op
    BenchmarkSetAllowHeaderWhen200-8         5560737               209.7 ns/op           336 B/op          3 allocs/op
    BenchmarkWithoutSetAllowHeader-8         6710652               163.7 ns/op           332 B/op          3 allocs/op
    
    • BenchmarkWithoutSetAllowHeader is without the middleware, to compare
    • BenchmarkSetAllowHeaderWhen200 is when the middleware is activated but not really used - it's a 200 response code
    • BenchmarkSetAllowHeaderWhen405 is when the middleware is activated and used
    opened by EwenQuim 0
  • Expose FindRoute on Mux to enable access to it in custom middleware

    Expose FindRoute on Mux to enable access to it in custom middleware

    We are building a custom middleware which needs to know the route that matched the current request path. Unfortunately, the only available option Match just returns a yay or nay. Since this method has access to the actual route that matches, can we add a FindRoute on Mux that will delegate the actual work to tree.FindRoute ?

    Is there an alternate way to determine the route that matches the current http request path in a custom middleware?

    opened by IDispose 0
  • Regex param doesn't match dots

    Regex param doesn't match dots

    Example program:

    package main
    
    import (
    	"fmt"
    	"net/http"
    	"net/http/httptest"
    
    	"github.com/go-chi/chi/v5"
    )
    
    func main() {
    	mux := chi.NewMux()
    	mux.Get("/{param:.+}.json", func(w http.ResponseWriter, r *http.Request) {
    		param := chi.URLParam(r, "param")
    		_, _ = fmt.Fprintf(w, "param=%s", param)
    	})
    
    	rec := httptest.NewRecorder()
    	req := httptest.NewRequest(http.MethodGet, "/param.json", nil)
    	mux.ServeHTTP(rec, req)
    
    	fmt.Printf("code: %d, body: %s\n", rec.Code, rec.Body)
    
    	rec = httptest.NewRecorder()
    	req = httptest.NewRequest(http.MethodGet, "/param.with.dots.json", nil)
    	mux.ServeHTTP(rec, req)
    
    	fmt.Printf("code: %d, body: %s\n", rec.Code, rec.Body)
    }
    

    Expected:

    code: 200, body: param=param
    code: 404, body: param=param.with.dots
    

    Got:

    code: 200, body: param=param
    code: 404, body: 404 page not found
    
    opened by Nyoroon 4
  • chi.Walk missing middlewares

    chi.Walk missing middlewares

    Hi,

    I was trying to use chi.Walk to get a report of all routes and the middlewares used by every route. I noticed that some of the middlewares were missing from some of the nested routes when using groups.

    Example routes:

    	r := chi.NewRouter()
    
    	r.Use(middleware.RequestID)
    
    	r.Get("/A", func(w http.ResponseWriter, r *http.Request) {})
    
    	r.Group(func(r chi.Router) {
    		r.Use(middleware.Timeout(2500 * time.Millisecond))
    
    		r.Get("/B", func(w http.ResponseWriter, r *http.Request) {})
    
    		r.Route("/C", func(r chi.Router) {
    
    			// Walk on the below route does not show the Timeout middleware
    			r.Get("/D", func(w http.ResponseWriter, r *http.Request) {})
    		})
    	})
    

    In the example above, I expected the C/D route to have both RequestId and Timeout middlewares. but chi.Walk only shows RequestID.

    It's possible I'm missing something here and this is behaving as expected.

    Go playground link: https://go.dev/play/p/HKh7cA35Bgx

    opened by ebabani 4
Releases(v5.0.8)
  • v5.0.8(Dec 7, 2022)

    • middleware.RealIP: few improvements https://github.com/go-chi/chi/pull/665 https://github.com/go-chi/chi/pull/684
    • middleware.Vary: fix https://github.com/go-chi/chi/pull/640
    • middleware.Recoverer: dont recover http.ErrAbortHandler https://github.com/go-chi/chi/pull/624
    • History of changes, see: https://github.com/go-chi/chi/compare/v5.0.7...v5.0.8
    Source code(tar.gz)
    Source code(zip)
  • v5.0.7(Nov 18, 2021)

  • v5.0.6(Nov 15, 2021)

  • v5.0.5(Oct 27, 2021)

    • Fix middleware.Recoverer under Go 1.17+ (again)
    • Update middleware.Heartbeat to respond to both HEAD and GET requests
    • History of changes, see: https://github.com/go-chi/chi/compare/v5.0.4...v5.0.5
    Source code(tar.gz)
    Source code(zip)
  • v5.0.4(Aug 29, 2021)

    • Fix middleware.Recoverer under Go 1.17+ (https://github.com/go-chi/chi/pull/633)
    • New in middleware: PageRoute and PathRewrite
    • New docs site! https://go-chi.io -- thank you @Shubhaankar-Sharma for all the amazing work :1st_place_medal: :100:
    • History of changes, see: https://github.com/go-chi/chi/compare/v5.0.3...v5.0.4
    Source code(tar.gz)
    Source code(zip)
  • v5.0.3(Apr 29, 2021)

  • v5.0.2(Mar 25, 2021)

  • v5.0.1(Mar 10, 2021)

  • v5.0.0(Feb 28, 2021)

    • chi v5, github.com/go-chi/chi/v5 introduces the adoption of Go's SIV to adhere to the current state-of-the-tools in Go.
    • chi v1.5.x did not work out as planned, as the Go tooling is too powerful and chi's adoption is too wide. The most responsible thing to do for everyone's benefit is to just release v5 with SIV, so I present to you all, chi v5 at github.com/go-chi/chi/v5. I hope someday the developer experience and ergonomics I've been seeking will still come to fruition in some form, see https://github.com/golang/go/issues/44550
    • History of changes: see https://github.com/go-chi/chi/compare/v1.5.4...v5.0.0
    Source code(tar.gz)
    Source code(zip)
  • v1.5.4(Feb 27, 2021)

    • Undo prior retraction in v1.5.3 as we prepare for v5.0.0 release
    • History of changes: see https://github.com/go-chi/chi/compare/v1.5.3...v1.5.4
    Source code(tar.gz)
    Source code(zip)
  • v1.5.3(Feb 21, 2021)

    • Update go.mod to go 1.16 with new retract directive marking all versions without prior go.mod support
    • History of changes: see https://github.com/go-chi/chi/compare/v1.5.2...v1.5.3
    Source code(tar.gz)
    Source code(zip)
  • v1.5.2(Feb 10, 2021)

    • Reverting allocation optimization as a precaution as go test -race fails.
    • Minor improvements, see history below
    • History of changes: see https://github.com/go-chi/chi/compare/v1.5.1...v1.5.2
    Source code(tar.gz)
    Source code(zip)
  • v1.5.1(Dec 6, 2020)

    • Performance improvement: removing 1 allocation by foregoing context.WithValue, thank you @bouk for your contribution (https://github.com/go-chi/chi/pull/555). Note: new benchmarks posted in README.
    • middleware.CleanPath: new middleware that clean's request path of double slashes
    • deprecate & remove chi.ServerBaseContext in favour of stdlib http.Server#BaseContext
    • plus other tiny improvements, see full commit history below
    • History of changes: see https://github.com/go-chi/chi/compare/v4.1.2...v1.5.1
    Source code(tar.gz)
    Source code(zip)
  • v1.5.0(Dec 6, 2020)

    • go.mod release and testing with Go's toolchain to ensure backwards-compatibility. See https://github.com/go-chi/chi/blob/master/CHANGELOG.md#v150-2020-11-12---now-with-gomod-support for full details. Thank you.
    • For existing projects who want to upgrade to the latest go.mod version, run: go get -u github.com/go-chi/[email protected], which will get you on the go.mod version line (as Go's mod cache may still remember v4.x).
    • Brand new systems can run go get -u github.com/go-chi/chi or go get -u github.com/go-chi/chi@latest to install chi, which will install v1.x+ built with go.mod support.
    Source code(tar.gz)
    Source code(zip)
  • v4.1.2(Jun 2, 2020)

    • fix that handles MethodNotAllowed with path variables, thank you @caseyhadden for your contribution
    • fix to replace nested wildcards correctly in RoutePattern, thank you @@unmultimedio for your contribution
    • History of changes: see https://github.com/go-chi/chi/compare/v4.1.1...v4.1.2
    Source code(tar.gz)
    Source code(zip)
  • v4.1.1(Apr 16, 2020)

    • fix for issue https://github.com/go-chi/chi/issues/411 which allows for overlapping regexp route to the correct handler through a recursive tree search, thanks to @Jahaja for the PR/fix!
    • new middleware.RouteHeaders as a simple router for request headers with wildcard support
    • updated the FileServer example to a much better implementation, see https://github.com/go-chi/chi/blob/master/_examples/fileserver/main.go
    • History of changes: see https://github.com/go-chi/chi/compare/v4.1.0...v4.1.1
    Source code(tar.gz)
    Source code(zip)
  • v4.1.0(Apr 1, 2020)

    • middleware.LogEntry: Write method on interface now passes the response header and an extra interface type useful for custom logger implementations.
    • middleware.WrapResponseWriter: minor fix
    • middleware.Recoverer: a bit prettier
    • History of changes: see https://github.com/go-chi/chi/compare/v4.0.4...v4.1.0
    Source code(tar.gz)
    Source code(zip)
  • v4.0.4(Mar 24, 2020)

    • middleware.Recoverer: new pretty stack trace printing (https://github.com/go-chi/chi/pull/496)
    • a few minor improvements and fixes
    • History of changes: see https://github.com/go-chi/chi/compare/v4.0.3...v4.0.4
    Source code(tar.gz)
    Source code(zip)
  • v4.0.3(Jan 9, 2020)

    • core: fix regexp routing to include default value when param is not matched
    • middleware: rewrite of middleware.Compress
    • middleware: suppress http.ErrAbortHandler in middleware.Recoverer
    • History of changes: see https://github.com/go-chi/chi/compare/v4.0.2...v4.0.3
    Source code(tar.gz)
    Source code(zip)
  • v4.0.2(Feb 26, 2019)

  • v4.0.1(Jan 21, 2019)

  • v4.0.0(Jan 10, 2019)

    • chi v4 requires Go 1.10.3+ (or Go 1.9.7+) - we have deprecated support for Go 1.7 and 1.8
    • router: respond with 404 on router with no routes (#362)
    • router: additional check to ensure wildcard is at the end of a url pattern (#333)
    • middleware: deprecate use of http.CloseNotifier (#347)
    • middleware: fix RedirectSlashes to include query params on redirect (#334)
    • History of changes: see https://github.com/go-chi/chi/compare/v3.3.4...v4.0.0
    Source code(tar.gz)
    Source code(zip)
  • v3.3.4(Jan 8, 2019)

    Minor middleware improvements. No changes to core library/router. Moving v3 into its own branch as a version of chi for Go 1.7, 1.8, 1.9, 1.10, 1.11

    History of changes: https://github.com/go-chi/chi/compare/v3.3.3...v3.3.4

    Master will switch into v4, where we will only support Go versions inline with Go's own policy, https://golang.org/doc/devel/release.html#policy (aka, last 2 versions)

    Source code(tar.gz)
    Source code(zip)
  • v3.3.3(Aug 27, 2018)

  • v3.3.2(Dec 22, 2017)

    • Support to route trailing slashes on mounted sub-routers (#281)
    • middleware: new ContentCharset to check matching charsets. Thank you @csucu for your community contribution!
    Source code(tar.gz)
    Source code(zip)
  • v3.3.1(Nov 20, 2017)

    • middleware: new AllowContentType handler for explicit whitelist of accepted request Content-Types
    • middleware: new SetHeader handler for short-hand middleware to set a response header key/value
    • Minor bug fixes
    Source code(tar.gz)
    Source code(zip)
  • v3.3.0(Oct 10, 2017)

    • New chi.RegisterMethod(method) to add support for custom HTTP methods, see _examples/custom-method for usage
    • Deprecated LINK and UNLINK methods from the default list, please use chi.RegisterMethod("LINK") and chi.RegisterMethod("UNLINK") in an init() function
    Source code(tar.gz)
    Source code(zip)
  • v3.1.3(Jul 25, 2017)

    func Walk(r Routes, walkFn WalkFunc) error
    
    type WalkFunc func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error
    
    Source code(tar.gz)
    Source code(zip)
  • v3.1.0(Jul 10, 2017)

    • Fix a few minor issues after v3 release
    • Move docgen sub-pkg to https://github.com/go-chi/docgen
    • Move render sub-pkg to https://github.com/go-chi/render
    • Add new URLFormat handler to chi/middleware sub-pkg to make working with url mime suffixes easier, ie. parsing /articles/1.json and /articles/1.xml. See comments in https://github.com/go-chi/chi/blob/master/middleware/url_format.go for example usage.
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0(Jun 23, 2017)

    • Major update to chi library with many exciting updates, but also some breaking changes
    • URL parameter syntax changed from /:id to /{id} for even more flexible routing, such as /articles/{month}-{day}-{year}-{slug}, /articles/{id}, and /articles/{id}.{ext} on the same router
    • Support for regexp for routing patterns, in the form of /{paramKey:regExp} for example: r.Get("/articles/{name:[a-z]+}", h) and chi.URLParam(r, "name")
    • Add Method and MethodFunc to chi.Router to allow routing definitions such as r.Method("GET", "/", h) which provides a cleaner interface for custom handlers like in _examples/custom-handler
    • Deprecating mux#FileServer helper function. Instead, we encourage users to create their own using file handler with the stdlib, see _examples/fileserver for an example
    • Add support for LINK/UNLINK http methods via r.Method() and r.MethodFunc()
    • Moved the chi project to its own organization, to allow chi-related community packages to be easily discovered and supported, at: https://github.com/go-chi
    • NOTE: please update your import paths to "github.com/go-chi/chi"
    • NOTE: chi v2 is still available at https://github.com/go-chi/chi/tree/v2
    Source code(tar.gz)
    Source code(zip)
Owner
go-chi
go-chi
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

Ozzo Framework 447 Dec 31, 2022
: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

Go Playgound 388 Dec 27, 2022
: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

CleverGo Web Framework 248 Nov 17, 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

defectivepixel 33 Aug 19, 2022
Lightweight Router for Golang using net/http standard library with custom route parsing, handler and context.

Go-Lightweight-Router Lightweight Router for Golang using net/http standard library with custom route parsing, handler and context. Further developmen

null 0 Nov 3, 2021
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

VividCortex 352 Nov 18, 2022
Bxog is a simple and fast HTTP router for Go (HTTP request multiplexer).

Bxog is a simple and fast HTTP router for Go (HTTP request multiplexer). Usage An example of using the multiplexer: package main import ( "io" "net

Eduard 106 Dec 26, 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

徐佳军 533 Dec 8, 2022
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

Vladimir Mihailenco 534 Dec 27, 2022
Go HTTP request router and web framework benchmark

Go HTTP Router Benchmark This benchmark suite aims to compare the performance of HTTP request routers for Go by implementing the routing structure of

Peter Kieltyka 28 Dec 27, 2022
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

Guilherme Caruso 55 Sep 27, 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

Razon Yang 22 Sep 27, 2022
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

Rafał Lorenz 143 Dec 16, 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

Julien Schmidt 14.8k 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

Daniel Imfeld 575 Dec 28, 2022
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

Go Playgound 132 Dec 1, 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

Nicolas Embriz 106 Dec 10, 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

amupxm [amir hossein mokarrami far] 5 Dec 27, 2021
Simple HTTP router for Go

ngamux Simple HTTP router for Go Installation Examples Todo Installation Run this command with correctly configured Go toolchain. go get github.com/ng

null 55 Dec 13, 2022