An extremely fast Go (golang) HTTP router that supports regular expression route matching. Comes with full support for building RESTful APIs.

Related tags

go golang framework router ozzo
Overview

ozzo-routing

GoDoc Build Status Coverage Status Go Report

You may consider using go-rest-api to jumpstart your new RESTful applications with ozzo-routing.

Description

ozzo-routing is a Go package that provides high performance and powerful HTTP routing capabilities for Web applications. It has the following features:

  • middleware pipeline architecture, similar to that of the Express framework.
  • extremely fast request routing with zero dynamic memory allocation (the performance is comparable to that of httprouter and gin, see the performance comparison below)
  • modular code organization through route grouping
  • flexible URL path matching, supporting URL parameters and regular expressions
  • URL creation according to the predefined routes
  • compatible with http.Handler and http.HandlerFunc
  • ready-to-use handlers sufficient for building RESTful APIs
  • graceful shutdown

If you are using fasthttp, you may use a similar routing package fasthttp-routing which is adapted from ozzo-routing.

Requirements

Go 1.13 or above.

Installation

In your Go project using go mod, run the following command to install the package:

go get github.com/go-ozzo/ozzo-routing/v2

Getting Started

For a complete RESTful application boilerplate based on ozzo-routing, please refer to the golang-restful-starter-kit. Below we describe how to create a simple REST API using ozzo-routing.

Create a server.go file with the following content:

package main

import (
	"log"
	"net/http"
	"github.com/go-ozzo/ozzo-routing/v2"
	"github.com/go-ozzo/ozzo-routing/v2/access"
	"github.com/go-ozzo/ozzo-routing/v2/slash"
	"github.com/go-ozzo/ozzo-routing/v2/content"
	"github.com/go-ozzo/ozzo-routing/v2/fault"
	"github.com/go-ozzo/ozzo-routing/v2/file"
)

func main() {
	router := routing.New()

	router.Use(
		// all these handlers are shared by every route
		access.Logger(log.Printf),
		slash.Remover(http.StatusMovedPermanently),
		fault.Recovery(log.Printf),
	)

	// serve RESTful APIs
	api := router.Group("/api")
	api.Use(
		// these handlers are shared by the routes in the api group only
		content.TypeNegotiator(content.JSON, content.XML),
	)
	api.Get("/users", func(c *routing.Context) error {
		return c.Write("user list")
	})
	api.Post("/users", func(c *routing.Context) error {
		return c.Write("create a new user")
	})
	api.Put(`/users/<id:\d+>`, func(c *routing.Context) error {
		return c.Write("update user " + c.Param("id"))
	})

	// serve index file
	router.Get("/", file.Content("ui/index.html"))
	// serve files under the "ui" subdirectory
	router.Get("/*", file.Server(file.PathMap{
		"/": "/ui/",
	}))

	http.Handle("/", router)
	http.ListenAndServe(":8080", nil)
}

Create an HTML file ui/index.html with any content.

Now run the following command to start the Web server:

go run server.go

You should be able to access URLs such as http://localhost:8080, http://localhost:8080/api/users.

Routes

ozzo-routing works by building a routing table in a router and then dispatching HTTP requests to the matching handlers found in the routing table. An intuitive illustration of a routing table is as follows:

Routes Handlers
GET /users m1, m2, h1, ...
POST /users m1, m2, h2, ...
PUT /users/<id> m1, m2, h3, ...
DELETE /users/<id> m1, m2, h4, ...

For an incoming request GET /users, the first route would match and the handlers m1, m2, and h1 would be executed. If the request is PUT /users/123, the third route would match and the corresponding handlers would be executed. Note that the token <id> can match any number of non-slash characters and the matching part can be accessed as a path parameter value in the handlers.

If an incoming request matches multiple routes in the table, the route added first to the table will take precedence. All other matching routes will be ignored.

The actual implementation of the routing table uses a variant of the radix tree data structure, which makes the routing process as fast as working with a hash table, thanks to the inspiration from httprouter.

To add a new route and its handlers to the routing table, call the To method like the following:

router := routing.New()
router.To("GET", "/users", m1, m2, h1)
router.To("POST", "/users", m1, m2, h2)

You can also use shortcut methods, such as Get, Post, Put, etc., which are named after the HTTP method names:

router.Get("/users", m1, m2, h1)
router.Post("/users", m1, m2, h2)

If you have multiple routes with the same URL path but different HTTP methods, like the above example, you can chain them together as follows,

router.Get("/users", m1, m2, h1).Post(m1, m2, h2)

If you want to use the same set of handlers to handle the same URL path but different HTTP methods, you can take the following shortcut:

router.To("GET,POST", "/users", m1, m2, h)

A route may contain parameter tokens which are in the format of <name:pattern>, where name stands for the parameter name, and pattern is a regular expression which the parameter value should match. A token <name> is equivalent to <name:[^/]*>, i.e., it matches any number of non-slash characters. At the end of a route, an asterisk character can be used to match any number of arbitrary characters. Below are some examples:

  • /users/<username>: matches /users/admin
  • /users/accnt-<id:\d+>: matches /users/accnt-123, but not /users/accnt-admin
  • /users/<username>/*: matches /users/admin/profile/address

When a URL path matches a route, the matching parameters on the URL path can be accessed via Context.Param():

router := routing.New()

router.Get("/users/<username>", func (c *routing.Context) error {
	fmt.Fprintf(c.Response, "Name: %v", c.Param("username"))
	return nil
})

Route Groups

Route group is a way of grouping together the routes which have the same route prefix. The routes in a group also share the same handlers that are registered with the group via its Use method. For example,

router := routing.New()
api := router.Group("/api")
api.Use(m1, m2)
api.Get("/users", h1).Post(h2)
api.Put("/users/<id>", h3).Delete(h4)

The above /api route group establishes the following routing table:

Routes Handlers
GET /api/users m1, m2, h1, ...
POST /api/users m1, m2, h2, ...
PUT /api/users/<id> m1, m2, h3, ...
DELETE /api/users/<id> m1, m2, h4, ...

As you can see, all these routes have the same route prefix /api and the handlers m1 and m2. In other similar routing frameworks, the handlers registered with a route group are also called middlewares.

Route groups can be nested. That is, a route group can create a child group by calling the Group() method. The router serves as the top level route group. A child group inherits the handlers registered with its parent group. For example,

router := routing.New()
router.Use(m1)

api := router.Group("/api")
api.Use(m2)

users := api.Group("/users")
users.Use(m3)
users.Put("/<id>", h1)

Because the router serves as the parent of the api group which is the parent of the users group, the PUT /api/users/<id> route is associated with the handlers m1, m2, m3, and h1.

Router

Router manages the routing table and dispatches incoming requests to appropriate handlers. A router instance is created by calling the routing.New() method.

Because Router implements the http.Handler interface, it can be readily used to serve subtrees on existing Go servers. For example,

router := routing.New()
http.Handle("/", router)
http.ListenAndServe(":8080", nil)

Handlers

A handler is a function with the signature func(*routing.Context) error. A handler is executed by the router if the incoming request URL path matches the route that the handler is associated with. Through the routing.Context parameter, you can access the request information in handlers.

A route may be associated with multiple handlers. These handlers will be executed in the order that they are registered to the route. The execution sequence can be terminated in the middle using one of the following two methods:

  • A handler returns an error: the router will skip the rest of the handlers and handle the returned error.
  • A handler calls Context.Abort(): the router will simply skip the rest of the handlers. There is no error to be handled.

A handler can call Context.Next() to explicitly execute the rest of the unexecuted handlers and take actions after they finish execution. For example, a response compression handler may start the output buffer, call Context.Next(), and then compress and send the output to response.

Context

For each incoming request, a routing.Context object is populated with the request information and passed through the handlers that need to handle the request. Handlers can get the request information via Context.Request and send a response back via Context.Response. The Context.Param() method allows handlers to access the URL path parameters that match the current route.

Using Context.Get() and Context.Set(), handlers can share data between each other. For example, an authentication handler can store the authenticated user identity by calling Context.Set(), and other handlers can retrieve back the identity information by calling Context.Get().

Reading Request Data

Context provides a few shortcut methods to read query parameters. The Context.Query() method returns the named URL query parameter value; the Context.PostForm() method returns the named parameter value in the POST or PUT body parameters; and the Context.Form() method returns the value from either POST/PUT or URL query parameters.

The Context.Read() method supports reading data from the request body and populating it into an object. The method will check the Content-Type HTTP header and parse the body data as the corresponding format. For example, if Content-Type is application/json, the request body will be parsed as JSON data. The public fields in the object being populated will receive the parsed data if the data contains the same named fields. For example,

func foo(c *routing.Context) error {
    data := &struct{
        A string
        B bool
    }{}

    // assume the body data is: {"A":"abc", "B":true}
    // data will be populated as: {A: "abc", B: true}
    if err := c.Read(&data); err != nil {
        return err
    }
}

By default, Context supports reading data that are in JSON, XML, form, and multipart-form data. You may modify routing.DataReaders to add support for other data formats.

Note that when the data is read as form data, you may use struct tag named form to customize the name of the corresponding field in the form data. The form data reader also supports populating data into embedded objects which are either named or anonymous.

Writing Response Data

The Context.Write() method can be used to write data of arbitrary type to the response. By default, if the data being written is neither a string nor a byte array, the method will will call fmt.Fprint() to write the data into the response.

You can call Context.SetWriter() to replace the default data writer with a customized one. For example, the content.TypeNegotiator will negotiate the content response type and set the data writer with an appropriate one.

Error Handling

A handler may return an error indicating some erroneous condition. Sometimes, a handler or the code it calls may cause a panic. Both should be handled properly to ensure best user experience. It is recommended that you use the fault.Recover handler or a similar error handler to handle these errors.

If an error is not handled by any handler, the router will handle it by calling its handleError() method which simply sets an appropriate HTTP status code and writes the error message to the response.

When an incoming request has no matching route, the router will call the handlers registered via the Router.NotFound() method. All the handlers registered via Router.Use() will also be called in advance. By default, the following two handlers are registered with Router.NotFound():

  • routing.MethodNotAllowedHandler: a handler that sends an Allow HTTP header indicating the allowed HTTP methods for a requested URL
  • routing.NotFoundHandler: a handler triggering 404 HTTP error

Serving Static Files

Static files can be served with the help of file.Server and file.Content handlers. The former serves files under the specified directories, while the latter serves the content of a single file. For example,

import (
	"github.com/go-ozzo/ozzo-routing/v2"
	"github.com/go-ozzo/ozzo-routing/v2/file"
)

router := routing.NewRouter()

// serve index file
router.Get("/", file.Content("ui/index.html"))
// serve files under the "ui" subdirectory
router.Get("/*", file.Server(file.PathMap{
	"/": "/ui/",
}))

Handlers

ozzo-routing comes with a few commonly used handlers in its subpackages:

Handler name Description
access.Logger records an entry for every incoming request
auth.Basic provides authentication via HTTP Basic
auth.Bearer provides authentication via HTTP Bearer
auth.Query provides authentication via token-based query parameter
auth.JWT provides JWT-based authentication
content.TypeNegotiator supports content negotiation by response types
content.LanguageNegotiator supports content negotiation by accepted languages
cors.Handler implements the CORS (Cross Origin Resource Sharing) specification from the W3C
fault.Recovery recovers from panics and handles errors returned by handlers
fault.PanicHandler recovers from panics happened in the handlers
fault.ErrorHandler handles errors returned by handlers by writing them in an appropriate format to the response
file.Server serves the files under the specified folder as response content
file.Content serves the content of the specified file as the response
slash.Remover removes the trailing slashes from the request URL and redirects to the proper URL

The following code shows how these handlers may be used:

import (
	"log"
	"net/http"
	"github.com/go-ozzo/ozzo-routing/v2"
	"github.com/go-ozzo/ozzo-routing/v2/access"
	"github.com/go-ozzo/ozzo-routing/v2/slash"
	"github.com/go-ozzo/ozzo-routing/v2/fault"
)

router := routing.New()

router.Use(
	access.Logger(log.Printf),
	slash.Remover(http.StatusMovedPermanently),
	fault.Recovery(log.Printf),
)

...

Third-party Handlers

The following third-party handlers are specifically designed for ozzo-routing:

Handler name Description
jwt.JWT supports JWT Authorization

ozzo-routing also provides adapters to support using third-party http.HandlerFunc or http.Handler handlers. For example,

router := routing.New()

// using http.HandlerFunc
router.Use(routing.HTTPHandlerFunc(http.NotFound))

// using http.Handler
router.Use(routing.HTTPHandler(http.NotFoundHandler))

3rd-Party Extensions and Code Examples

Benchmarks

Last updated on Jan 6, 2017

Ozzo-routing is very fast, thanks to the radix tree data structure and the usage of sync.Pool (the idea was originally from HttpRouter and Gin). The following table (by running go-http-routing-benchmark) shows how ozzo-routing compares with Gin, HttpRouter, and Martini in performance.

BenchmarkOzzo_GithubAll                    50000             37989 ns/op               0 B/op          0 allocs/op
BenchmarkEcho_GithubAll                    20000             91003 ns/op            6496 B/op        203 allocs/op
BenchmarkGin_GithubAll                     50000             26717 ns/op               0 B/op          0 allocs/op
BenchmarkHttpRouter_GithubAll              50000             36052 ns/op           13792 B/op        167 allocs/op
BenchmarkMartini_GithubAll                   300           4162283 ns/op          228216 B/op       2483 allocs/op

BenchmarkOzzo_GPlusAll                   1000000              1732 ns/op               0 B/op          0 allocs/op
BenchmarkEcho_GPlusAll                    300000              4523 ns/op             416 B/op         13 allocs/op
BenchmarkGin_GPlusAll                    1000000              1171 ns/op               0 B/op          0 allocs/op
BenchmarkHttpRouter_GPlusAll             1000000              1533 ns/op             640 B/op         11 allocs/op
BenchmarkMartini_GPlusAll                  20000             75634 ns/op           14448 B/op        165 allocs/op

BenchmarkOzzo_ParseAll                    500000              3318 ns/op               0 B/op          0 allocs/op
BenchmarkEcho_ParseAll                    200000              7336 ns/op             832 B/op         26 allocs/op
BenchmarkGin_ParseAll                    1000000              2075 ns/op               0 B/op          0 allocs/op
BenchmarkHttpRouter_ParseAll             1000000              2034 ns/op             640 B/op         16 allocs/op
BenchmarkMartini_ParseAll                  10000            122002 ns/op           25600 B/op        276 allocs/op

Credits

ozzo-routing has referenced many popular routing frameworks, including Express, Martini, httprouter, and gin.

Issues
  • Strange error on https with 1503 0100 0202 0a

    Strange error on https with 1503 0100 0202 0a

    I start two servers: http on port 8080 https on port 8088

    go func() {
            s := app.C.GetString("WebServer.Domain") + ":" + app.C.GetString("WebServer.PortHTTPS")
            l.Info("Start Serving HTTPS on " + s)
            err := http.ListenAndServeTLS(s, "./ssl/cert.pem", "./ssl/key.pem", nil)
            if err != nil {
                l.Emergency(err.Error())
            }
        }()
    
        s := app.C.GetString("WebServer.Domain") + ":" + app.C.GetString("WebServer.PortHTTP")
        l.Info("Start Serving HTTP on " + s)
        // Запуск HTTP сервера и редирект всех входящих запросов на HTTPS
        err := http.ListenAndServe(s, http.HandlerFunc(redirectToHttps))
        if err != nil {
            l.Emergency(err.Error())
        }
    

    If i connecting to port 8088 without https begins, Chrome will download a file as follows:

    0000000: 1503 0100 0202 0a
    

    What this?

    opened by kolkov 10
  • 关于context中handler是否能够放到router中

    关于context中handler是否能够放到router中

    强哥,context中的router是否可以放在router的结构体中呢?该怎么做

    opened by skyleelove 8
  • Russian translation of README.md

    Russian translation of README.md

    Hi! I think it will be very helpful for the popularization OZZO in Russia.

    opened by kolkov 7
  • 关于部分函数的用法

    关于部分函数的用法

    强哥,当我调用Use()后 router.Use( // all these handlers are shared by every route access.Logger(log.Printf), slash.Remover(http.StatusMovedPermanently), fault.Recovery(log.Printf), ) 之后的操作我没太明白,access.Logger(log.Printf),slash.Remover(http.StatusMovedPermanently),fault.Recovery(log.Printf),在以后的程序中是如何使用的呢?

    opened by skyleelove 7
  • VGO support.

    VGO support.

    Hi! Are you planning to add VGO support?

    opened by kolkov 6
  • Exposing Find

    Exposing Find

    I raised a ticket to discuss this proposal about a month ago:

    https://github.com/go-ozzo/ozzo-routing/issues/42

    The change is very slight, just exposing the Find method on the router. The purpose of this is to allow an API to map an internal or "self" link to a database entity, by determining the ID of the object that link represents.

    I've also moved the Find method up in its file to keep all the public methods together.

    opened by jackwhelpton 6
  • Add support for fasthttp

    Add support for fasthttp

    It would be great adding support for fasthttp in ozzo-routing. Fasthttp is extremely fast and it doesn't allocate memory in fast paths. So fasthttp-backed ozzo-routing will allow writing low-overhead http servers with advanced routing capabilities.

    opened by valyala 6
  • Error in JWT example

    Error in JWT example

    Hi! I think this is a error:

     token, err := auth.NewJWT(jwt.StandardClaims{
             Id: id
           }, signingKey)
    
    func NewJWT(claims jwt.MapClaims, signingKey string, signingMethod ...jwt.SigningMethod) (string, error) {
        var sm jwt.SigningMethod = jwt.SigningMethodHS256
        if len(signingMethod) > 0 {
            sm = signingMethod[0]
        }
        return jwt.NewWithClaims(sm, claims).SignedString([]byte(signingKey))
    }
    
    opened by kolkov 5
  • How to Organize a project?

    How to Organize a project?

    In PHP we create root folder and project in it. Such as:

    root
    -config
    -controllers
    -models
    -views
    -utils
    -vendor
    etc.
    

    My project is an angular.js project. I need to have one or more index.html file(s) which will load some .js and .css files. And then Angular.js on frontend will use REST API on backend.

    Golang is not a PHP. Qiang, what is the best way to organaize a project in the root folder? What do you think about this? Thanks!

    opened by kolkov 5
  • Further development of ozzo framework

    Further development of ozzo framework

    Qiang, do you plan to develop ozzo like yii in the future? I like yii, but I think that my new project is to big for yii. I would like to start developing a big project on golang using ozzo right now.) But I would like to understand the perspectives...

    opened by kolkov 5
  • Why not use a httprouter in your go-rest-api template?

    Why not use a httprouter in your go-rest-api template?

    why don't you use your http router as your main router (stable high performance). (fasthttp,gin and ozzo-routing and unexpectedly slow in tests)

    opened by tvitcom 0
  • Can we use this feature to populate all nested struct fields?

    Can we use this feature to populate all nested struct fields?

    Hi! I try to find the way to populate DDD aggregate with simple joined query. At this moment it possible only by giving all needed fields in select query. I whant to use this way to populate all struct with nested struct fields at once. https://stackoverflow.com/a/13153422

    For example:

    type Wagon struct {
        Wagon
        State WagonState
        Location WagonLocation
    }
    

    with

    ...
    Select(
        "w.*",
        "ws.*",
        "wl.*"
    ).From("wagon w").
    InnerJoin("wagon_state ws", dbx.NewExp("ws.id=w.state_id")).
    InnerJoin("wagon_location wl", dbx.NewExp("wl.id=w.location_id")).
    ...
    

    Is it possible to add to this lib?

    opened by kolkov 0
  • Reading array query parameter as `[]time.Time`?

    Reading array query parameter as `[]time.Time`?

    Reading array query parameters doesn't seem to work with common non primitive types (eg. []time.Time, []uuid.UUID, etc.).

    Example:

    // url: http://localhost:8090/api/test?Names=test1&Dates=2020-10-11T21%3A00%3A00.000Z
    
    data := &struct{
        Names []string
        Dates []time.Time
    }{}
    
    ctx.Read(data) // result: { Names: [ "test1" ], Dates: [] }
    

    I guess if an alias type with custom encoding.TextUnmarshaler is provided it would work, but that seems redundant because the non slice version is correctly unmarshalized.

    opened by ganigeorgiev 0
  • How better set response encoding?

    How better set response encoding?

    Hi! I am using content.TypeNegotiator(content.JSON) But for some reason there is no encoding set (charset=UTF-8). How do I better set the response encoding for the all application at once? Thank you!

    opened by Kalinin-Andrey 0
  • Add function to delete internal context.data

    Add function to delete internal context.data

    We use c.Set("isUser", true) to pass data to other handlers, sometimes in complex functions, we may use a few handlers inside a handler, some handlers may required some internal data to be set while other handlers do not need those data, so hope to have a function to "delete" the context.data

    func abc123(c *routing.Context) error {
    
        c.Set("name1", true)
        err := cde123(c)
    
        c.Delete("name1") // <-- hope to have something like that to delete internal data
        err := cde123(c)
    
        return nil
    }
    
    opened by byanjiong 0
  • Serving Static Html file for not found endpoints.

    Serving Static Html file for not found endpoints.

    I was going through the documentation and I saw the explanation given about error handling.

    What I am trying to achieve is being able to return an html file in a situation where the endpoint is not provided. I wanted to just go ahead and add my function for 404/not found errors.

    But, I was concerned about it interfering with situations where I return a 404 itself. E.g: When a user makes a request to get information about a user and the user isn't available.

    Your response and suggestion would be greatly appreciated.

    Thanks

    opened by tonespy 0
  • `http: multiple response.WriteHeader calls` when using fault.Recovery

    `http: multiple response.WriteHeader calls` when using fault.Recovery

    test code is:

    package main
    
    import (
        "github.com/go-ozzo/ozzo-routing"
        "github.com/go-ozzo/ozzo-routing/fault"
        "log"
        "net/http"
    )
    
    func main() {
        router := routing.New()
        router.Use(
            fault.Recovery(log.Printf, func(c *routing.Context, err error) error {
                c.Write(err)
                return nil 
            }), 
        )   
        http.Handle("/", router)
        http.ListenAndServe(":8123", nil)
    }
    

    on error occurred, it will log an additional message: http: multiple response.WriteHeader calls

    2018/01/24 12:08:54 Not Found
    2018/01/24 12:08:54 http: multiple response.WriteHeader calls
    
    opened by darasion 0
  • HTTPError with StatusBadRequest return a response with 500 Internal Error

    HTTPError with StatusBadRequest return a response with 500 Internal Error

    Hello,

    In the API layer of my app, Every call can return HTTPError with various Status.

    For exemple in case of a no found objet for a GET call I return : return routing.NewHTTPError(http.StatusNotFound, err.Error()) The response head will be correctly set.

    But when I use the http.StatusBadRequest in the exact same way (for example a POST with invalid validation):

    return routing.NewHTTPError(http.StatusBadRequest)

    The response header is set to 500 Internal Server Error instead of 400 Bad request.

    Thanks, Regards, Arthur

    opened by asaintgenis 1
  • Is there a way to get the name of current route?

    Is there a way to get the name of current route?

    Im want to do some permission check in middleware.

    opened by puper 0
  • NewContext() is not populating parameters from provided URL

    NewContext() is not populating parameters from provided URL

    I'm trying to write a unit test, as I would in Express+Supertest. I'm finding that when I provide a test URL, that the parameters are not parsed.

    import (
    	"context"
    	"net/http"
    	"net/http/httptest"
    	"testing"
    
    	"github.com/go-ozzo/ozzo-routing"
    	"github.com/go-ozzo/ozzo-routing/content"
    	"github.com/stretchr/testify/assert"
    )
    
    func TestContextParamsPopulatedByOzzo(test *testing.T) {
    	assert := assert.New(test)
    
    	// Initialize app
    	router := routing.New()
    	router.Get("/test/<id>", routing.NotFoundHandler)
    
    	// Mock up a request
    	res := httptest.NewRecorder()
    	req, err := http.NewRequest("GET", "/test/23", nil)
    	assert.NoError(err)
    
    	// Mock up a routing context
    	routeCtx := routing.NewContext(res, req)
    
    	// Sanity check
    	assert.Equal("23", routeCtx.Param("id"))
    }
    
    opened by drauschenbach 0
Releases(v2.3.0)
Owner
Ozzo Framework
Ozzo is a Go (golang) framework consisting of fully decoupled packages supporting rapid Web application development.
Ozzo Framework
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 500 Aug 16, 2021
A powerful HTTP router and URL matcher for building Go web servers with 🦍

gorilla/mux https://www.gorillatoolkit.org/pkg/mux Package gorilla/mux implements a request router and dispatcher for matching incoming requests to th

Gorilla Web Toolkit 15.1k Sep 13, 2021
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 13.1k Sep 11, 2021
Go Router + Middleware. Your Contexts.

gocraft/web gocraft/web is a Go mux and middleware package. We deal with casting and reflection so YOUR code can be statically typed. And we're fast.

null 1.4k Sep 7, 2021
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 52 Aug 18, 2021
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 103 May 25, 2021
lightweight, idiomatic and composable router for building Go HTTP services

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

go-chi 10.1k Sep 12, 2021
A high performance fasthttp request router that scales well

FastHttpRouter FastHttpRouter is forked from httprouter which is a lightweight high performance HTTP request router (also called multiplexer or just m

招牌疯子 873 Jul 29, 2021
Echo Inspired Stand Alone URL Router

Vestigo - A Standalone Golang URL Router Abstract Many fast Golang URL routers are often embedded inside frameworks. Vestigo is a stand alone url rout

null 263 Jul 27, 2021
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 Sep 7, 2021
: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 251 Aug 19, 2021
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

徐佳军 504 Sep 8, 2021
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 Aug 20, 2021
: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 383 Aug 26, 2021
xmux is a httprouter fork on top of xhandler (net/context aware)

Xmux Xmux is a lightweight high performance HTTP request muxer on top xhandler. Xmux gets its speed from the fork of the amazing httprouter. Route par

Olivier Poitrey 90 Jun 12, 2021
Router socks. One port socks for all the others.

Router socks The next step after compromising a machine is to enumerate the network behind. Many tools exist to expose a socks port on the attacker's

null 50 Sep 7, 2021
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 115 Jul 14, 2021
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 102 Jun 15, 2021
Lightning Fast HTTP Multiplexer

bone What is bone ? Bone is a lightweight and lightning fast HTTP Multiplexer for Golang. It support : URL Parameters REGEX Parameters Wildcard routes

Go-zoo 1.3k Sep 4, 2021