:rotating_light: Is a lightweight, fast and extensible zero allocation HTTP router for Go used to create customizable frameworks.

Overview

LARS

Project status Build Status Coverage Status Go Report Card GoDoc License Gitter

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 pure which is essentially a pure version of lars

Why Another HTTP Router?

Have you ever been painted into a corner by a framework, ya me too! and I've noticed that allot of routers out there, IMHO, are adding so much functionality that they are turning into Web Frameworks, (which is fine, frameworks are important) however, not at the expense of flexibility and configurability. So with no further ado, introducing LARS an HTTP router that can be your launching pad in creating a framework for your needs. How? Context is an interface see example here, where you can add as little or much as you want or need and most importantly...under your control.

Key & Unique Features

  • Context is an interface - this allows passing of framework/globals/application specific variables. example
  • Smart Route Logic - helpful logic to help prevent adding bad routes, keeping your url's consistent. i.e. /user/:id and /user/:user_id - the second one will fail to add letting you know that :user_id should be :id
  • Uber simple middleware + handlers - middleware and handlers actually have the exact same definition!
  • Custom Handlers - can register custom handlers for making other middleware + handler patterns usable with this router; the best part about this is can register one for your custom context and not have to do type casting everywhere see here
  • Diverse handler support - Full support for standard/native http Handler + HandlerFunc + some others see here
    • When Parsing a form call Context's ParseForm amd ParseMulipartForm functions and the URL params will be added into the Form object, just like query parameters are, so no extra work
  • Fast & Efficient - lars uses a custom version of httprouter so incredibly fast and efficient.

Installation

go get -u github.com/go-playground/lars

Usage

Below is a simple example, for a full example see here

package main

import (
	"fmt"
	"net/http"

	"github.com/go-playground/lars"
	mw "github.com/go-playground/lars/_examples/middleware/logging-recovery"
)

func main() {
	l := lars.New()
	// LoggingAndRecovery is just an example copy paste and modify to your needs
	l.Use(mw.LoggingAndRecovery)

	l.Get("/", HelloWorld)

	http.ListenAndServe(":3007", l.Serve())
}

// HelloWorld ...
func HelloWorld(c lars.Context) {
	c.Response().Write([]byte("Hello World"))

	// this will also work, Response() complies with http.ResponseWriter interface
	fmt.Fprint(c.Response(), "Hello World")
}

URL Params

l := l.New()

// the matching param will be stored in the Context's params with name "id"
l.Get("/user/:id", UserHandler)

// serve css, js etc.. c.Param(lars.WildcardParam) will return the remaining path if 
// you need to use it in a custom handler...
l.Get("/static/*", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) 

...

Note: Since this router has only explicit matches, you can not register static routes and parameters for the same path segment. For example you can not register the patterns /user/new and /user/:user for the same request method at the same time. The routing of different request methods is independent from each other. I was initially against this, and this router allowed it in a previous version, however it nearly cost me in a big app where the dynamic param value say :type actually could have matched another static route and that's just too dangerous, so it is no longer allowed.

Groups

l.Use(LoggingAndRecovery)
...
l.Post("/users/add", ...)

// creates a group for user + inherits all middleware registered using l.Use()
user := l.Group("/user/:userid")
user.Get("", ...)
user.Post("", ...)
user.Delete("/delete", ...)

contactInfo := user.Group("/contact-info/:ciid")
contactinfo.Delete("/delete", ...)

// creates a group for others + inherits all middleware registered using l.Use() + adds 
// OtherHandler to middleware
others := l.GroupWithMore("/others", OtherHandler)

// creates a group for admin WITH NO MIDDLEWARE... more can be added using admin.Use()
admin := l.GroupWithNone("/admin")
admin.Use(SomeAdminSecurityMiddleware)
...

Custom Context + Avoid Type Casting / Custom Handlers

...
// MyContext is a custom context
type MyContext struct {
	*lars.Ctx  // a little dash of Duck Typing....
}

// CustomContextFunction is a function that is specific to your applications needs that you added
func (mc *MyContext) CustomContextFunction() {
	// do something
}

// newContext is the function that creates your custom context +
// contains lars's default context
func newContext(l *lars.LARS) lars.Context {
	return &MyContext{
		Ctx:        lars.NewContext(l),
	}
}

// casts custom context and calls you custom handler so you don;t have to type cast lars.Context everywhere
func castCustomContext(c lars.Context, handler lars.Handler) {
	// could do it in all one statement, but in long form for readability
	h := handler.(func(*MyContext))
	ctx := c.(*MyContext)

	h(ctx)
}

func main() {
	l := lars.New()
	l.RegisterContext(newContext) // all gets cached in pools for you
	l.RegisterCustomHandler(func(*MyContext) {}, castCustomContext)
	l.Use(Logger)

	l.Get("/", Home)

	http.ListenAndServe(":3007", l.Serve())
}

// Home ...notice the receiver is *MyContext, castCustomContext handled the type casting for us
// quite the time saver if you ask me.
func Home(c *MyContext) {
	c.CustomContextFunction()
	...
}

Decoding Body

For full example see here. currently JSON, XML, FORM + Multipart Form's are support out of the box.

	// first argument denotes yes or no I would like URL query parameter fields
	// to be included. i.e. 'id' in route '/user/:id' should it be included.
	// run, then change to false and you'll see user.ID is not populated.
	if err := c.Decode(true, maxBytes, &user); err != nil {
		log.Println(err)
	}

Misc

...
// can register multiple handlers, the last is considered the last in the chain and others 
// considered middleware, but just for this route and not added to middleware like l.Use() does.
l.Get(/"home", AdditionalHandler, HomeHandler)

// set custom 404 ( not Found ) handler
l.Register404(404Handler)

// Redirect to or from ending slash if route not found, default is true
l.SetRedirectTrailingSlash(true)

// Handle 405 ( Method Not allowed ), default is false
l.SetHandle405MethodNotAllowed(false)

// automatically handle OPTION requests; manually configured
// OPTION handlers take precedence. default true
l.SetAutomaticallyHandleOPTIONS(set bool)

// register custom context
l.RegisterContext(ContextFunc)

// Register custom handler type, see https://github.com/go-playground/lars/blob/master/util.go#L62
// for example handler creation
l.RegisterCustomHandler(interface{}, CustomHandlerFunc)

// NativeChainHandler is used as a helper to create your own custom handlers, or use custom handlers 
// that already exist an example usage can be found here 
// https://github.com/go-playground/lars/blob/master/util.go#L86, below is an example using nosurf CSRF middleware

l.Use(nosurf.NewPure(lars.NativeChainHandler))


// Context has 2 methods of which you should be aware of ParseForm and ParseMulipartForm, they just call the 
// default http functions but provide one more additional feature, they copy the URL params to the request 
// Forms variables, just like Query parameters would have been.
// The functions are for convenience and are totally optional.

Special Note

I don't know if it was an oversight or just an assumption about how middleware would be used with Go 1.7's new context integration into the *http.Request but there are a few quirks. As you know lars handles multiple handler types, including the native handler, this functionality is possible because of the way lar handles the middleware; lars does not chain the middleware in the normal way, but rather calles each in sequence; because of this all you have to do is call c.Next() or it has already been wrapped to do so for you transparently. OK getting back to the point, if you are not using lars.Context to set the context information you will have to set the request object so that the information gets back to the calling package. eg.

// because 'r' is a copy of a pointer to allow the information to get
// back to the caller, need to set the value of 'r' as below with '*r'
func(w http.ResponseWriter, r *http.Request) {
	*r = *r.WithContext(context.WithValue(r.Context(), 0, "testval1"))
}

this is not an issue specific to lars, but a quirk of the way context is tied to the http.Request object.

Middleware

There are some pre-defined middlewares within the middleware folder; NOTE: that the middleware inside will comply with the following rule(s):

  • Are completely reusable by the community without modification

Other middleware will be listed under the _examples/middleware/... folder for a quick copy/paste modify. as an example a logging or recovery middleware are very application dependent and therefore will be listed under the _examples/middleware/...

Benchmarks

Run on MacBook Pro (15-inch, 2017) 3.1 GHz Intel Core i7 16GB DDR3 using Go version go1.9.2 darwin/amd64

NOTICE: lars uses a custom version of httprouter, benchmarks can be found here

go test -bench=. -benchmem=true
#GithubAPI Routes: 203
   LARS: 49032 Bytes

#GPlusAPI Routes: 13
   LARS: 3640 Bytes

#ParseAPI Routes: 26
   LARS: 6632 Bytes

#Static Routes: 157
   LARS: 30120 Bytes

goos: darwin
goarch: amd64
pkg: github.com/joeybloggs/go-http-routing-benchmark
BenchmarkLARS_Param        	20000000	        51.6 ns/op	       0 B/op	       0 allocs/op
BenchmarkLARS_Param5       	20000000	        85.7 ns/op	       0 B/op	       0 allocs/op
BenchmarkLARS_Param20      	10000000	       215 ns/op	       0 B/op	       0 allocs/op
BenchmarkLARS_ParamWrite   	20000000	        94.3 ns/op	       0 B/op	       0 allocs/op
BenchmarkLARS_GithubStatic 	20000000	        68.7 ns/op	       0 B/op	       0 allocs/op
BenchmarkLARS_GithubParam  	20000000	       103 ns/op	       0 B/op	       0 allocs/op
BenchmarkLARS_GithubAll    	  100000	     21066 ns/op	       0 B/op	       0 allocs/op
BenchmarkLARS_GPlusStatic  	30000000	        53.1 ns/op	       0 B/op	       0 allocs/op
BenchmarkLARS_GPlusParam   	20000000	        70.3 ns/op	       0 B/op	       0 allocs/op
BenchmarkLARS_GPlus2Params 	20000000	        84.4 ns/op	       0 B/op	       0 allocs/op
BenchmarkLARS_GPlusAll     	 2000000	       894 ns/op	       0 B/op	       0 allocs/op
BenchmarkLARS_ParseStatic  	20000000	        53.5 ns/op	       0 B/op	       0 allocs/op
BenchmarkLARS_ParseParam   	20000000	        60.4 ns/op	       0 B/op	       0 allocs/op
BenchmarkLARS_Parse2Params 	20000000	        68.7 ns/op	       0 B/op	       0 allocs/op
BenchmarkLARS_ParseAll     	 1000000	      1602 ns/op	       0 B/op	       0 allocs/op
BenchmarkLARS_StaticAll    	  100000	     13777 ns/op	       0 B/op	       0 allocs/op

Package Versioning

I'm jumping on the vendoring bandwagon, you should vendor this package as I will not be creating different version with gopkg.in like allot of my other libraries.

Why? because my time is spread pretty thin maintaining all of the libraries I have + LIFE, it is so freeing not to worry about it and will help me keep pouring out bigger and better things for you the community.

This package is inspired by the following

Licenses

  • MIT License (MIT), Copyright (c) 2015 Dean Karn
  • BSD License, Copyright (c) 2013 Julien Schmidt. All rights reserved.
Issues
  • Provide a way to clone Context

    Provide a way to clone Context

    Hi. I'm in a process of adding OpenTracing to our app which uses lars. To do that I've created custom context to simplify some operations. The way the OpenTracing API works is that it injects some information about the spans (https://github.com/opentracing/specification/blob/master/specification.md) into the Context object to be propagated down into the call chain (or via headers to other services being called in the process).

    The problem arises when I create multiple spans in the same request. My function looks more or less like this:

    func (c CustomContext) StartSpan(operationName string) (opentracing.Span, *CustomContext) {
    	span, newCtx := opentracing.StartSpanFromContext(c.Context(), operationName)
    
    	c.WithContext(newCtx)
    	return span, &c
    }
    

    The obvious problem is that when it is being called more than once the current Context is being altered by every call of this function. What I want is to return copy of the context and use it in subsequent functions without altering the "parent" Context.

    func handler(c *CustomContext) {
       spanA, newCtx := c.StartSpan("spanA")
       defer spanA.Finish()
       subFunc(newCtx)
    
       spanC, _ := c.StartSpan("spanC")
       defer spanC.FInish()
    }
    
    func subFunc(c *CustomContext) {
       spanB, _ := c.StartSpan("spanB")
       // ...
       defer spanB.FInish()
    
    }
    

    this currently result in spans like this:

                   ------------
                   | RootSpan |
                   ------------
                      | 
                ---------
                | SpanA |
                ---------
                       |
                    ---------
                    | SpanB |
                    ---------
                         |
                    ---------
                    | SpanC |
                    ---------
    

    proper hierarchy should look like this:

                   ------------
                   | RootSpan |
                   ------------
                     |       |
                ---------  ---------
                | SpanA |  | SpanC |
                ---------  ---------
                       |
                    ---------
                    | SpanB |
                    ---------
    

    The only solution to this is I can see right now is to: a) create a full deep clone of the lars.Context struct b) ditch lars.Context in the handler and operate on standard Context (accessible via lars.Context.Context()) - but that would mean that in functions that needs to operate on lars.Context I would need to pass two of them (lars.Context and std.Context) which is not ideal

    I'm open to any suggestions how to deal with it.

    opened by harnash 10
  • Subgroups with middlewares are overriding parent groups middlewares

    Subgroups with middlewares are overriding parent groups middlewares

    Hi @joeybloggs ,

    I'm doing some testing with this router, and I found an issue. Here is an example:

    a := server.Group("/a", aM)
    a.Get("/test", func(ctx *internal.Ctx) {
    	ctx.JSON(http.StatusOK, "a-ok")
    })
    
    b := a.Group("/b", bM)
    b.Get("/test", func(ctx *internal.Ctx) {
    	ctx.JSON(http.StatusOK, "b-ok")
    })
    
    c := b.Group("/c", cM)
    c.Get("/test", func(ctx *internal.Ctx) {
    	ctx.JSON(http.StatusOK, "c-ok")
    })
    
    func aM(ctx *internal.Ctx) {
    	ctx.Next()
    }
    
    func bM(ctx *internal.Ctx) {
    	ctx.Next()
    }
    
    func cM(ctx *internal.Ctx) {
    	ctx.Next()
    }
    

    And this is the behavior:

    1. /a/test executes the aM. Everthing OK.
    2. /a/b/test executes only bM, it does not execute aM. But it should.
    3. /a/b/c/test executes only cM, it does not execute aM and bM. But it should execute them all.

    If this is a bug, I hope it will be fixed ASAP. From a lot of routers out there this one seems pretty good to me, and this issue is blocking me to migrate to it.

    bug 
    opened by es-lab 5
  • RequestEnd is getting called twice in context

    RequestEnd is getting called twice in context

    I have a custom context

    import (
    	"net/http"
    	"github.com/go-playground/lars"
    	"novyy/database"
    	"novyy/redis"
    	"novyy/structures"
    	"strings"
    	"github.com/Sirupsen/logrus"
    	"gopkg.in/mgo.v2/bson"
    	"novyy/utils"
    	"fmt"
    )
    
    var (
    	contextDatabase *database.Instance
    	contextTemporaryStorage *redis.TemporaryStorage
    	contextLogger *logrus.Logger
    	contextEmailSender *utils.EmailSender
    
    	limitRequestPerIP int
    	limitRequestPerAuthorizedIP int
    )
    
    // This is a contrived example of how I would use in production
    
    // ApplicationGlobals houses all the application info for use.
    type ApplicationGlobals struct {
    	// Permanent
    	Logger *logrus.Logger
    	DB *database.Instance
    	Cache *redis.TemporaryStorage
    	Email *utils.EmailSender
    
    	// Changes per request
    	AccountId bson.ObjectId
    	Blocked bool
    }
    
    // Reset gets called just before a new HTTP request starts calling
    // middleware + handlers
    func (g *ApplicationGlobals) Reset() {
    	g.AccountId = ""
    	g.Blocked = false
    }
    
    // Done gets called after the HTTP request has completed right before
    // Context gets put back into the pool
    func (g *ApplicationGlobals) Done() {
    
    }
    
    func newGlobals() *ApplicationGlobals {
    	return &ApplicationGlobals{
    		Logger: contextLogger,
    		DB: contextDatabase,
    		Cache: contextTemporaryStorage,
    		Email: contextEmailSender,
    	}
    }
    
    // MyContext is a custom context
    type NovyyContext struct {
    	*lars.Ctx  // a little dash of Duck Typing....
    	AppContext *ApplicationGlobals
    }
    
    // RequestStart overriding
    func (c *NovyyContext) RequestStart(w http.ResponseWriter, r *http.Request) {
    	fmt.Println("REQUEST BEGIN") // !!!!! look here
    
    	c.AppContext.Reset()
    	c.Ctx.RequestStart(w, r) // MUST be called!
    
    	w.Header().Set("Content-Type", "application/json")
    }
    
    // RequestEnd overriding
    func (c *NovyyContext) RequestEnd() {
    	fmt.Println("REQUEST END") // !!!!! look here
    	c.AppContext.Done()
    	c.Ctx.RequestEnd() // MUST be called!
    }
    
    func NewContext(l *lars.LARS) lars.Context {
    	return &NovyyContext{
    		Ctx:        lars.NewContext(l),
    		AppContext: newGlobals(),
    	}
    }
    
    func CastCustomContext(c lars.Context, handler lars.Handler) {
    	// could do it in all one statement, but in long form for readability
    	h := handler.(func(*NovyyContext))
    	ctx := c.(*NovyyContext)
    
    	h(ctx)
    }
    
    func SetSharedGlobals(db *database.Instance, temporaryStorage *redis.TemporaryStorage,
    	logger *logrus.Logger, sender *utils.EmailSender) {
    
    	contextDatabase = db
    	contextTemporaryStorage = temporaryStorage
    	contextLogger = logger
    	contextEmailSender = sender
    }
    
    func SetLimits(rpIP, rpaIP int) {
    	limitRequestPerIP = rpIP
    	limitRequestPerAuthorizedIP = rpaIP
    }
    

    Set up

    	Router = lars.New()
    
    	if !Config.Environment.Production {
    		Router.Use(DebugRouter)
    		log.Info("Router debugger is enabled")
    	}
    
    	routing.SetLimits(Config.AntiSpam.RequestsPerIP, Config.AntiSpam.RequestsPerAuthorizedIP)
    	emailSender := utils.NewSender(Config.Email.Username, Config.Email.Password)
    	routing.SetSharedGlobals(Database, TemporaryStorage, log.StandardLogger(), &emailSender)
    
    	Router.RegisterContext(routing.NewContext) // all gets cached in pools for you
    	Router.RegisterCustomHandler(func(*routing.NovyyContext) {}, routing.CastCustomContext)
    
    	Router.Register404(routing.NotFound)
    
    	// API version 1
    	apiV1 := Router.Group("/v1")
    	apiV1.Use(routing.AntiSpamMiddleware)
    	// - Authorization
    	auth := apiV1.Group("/auth")
    	auth.Use(routing.SimpleAuthorizationMiddleware) // requires API key
    	auth.Post("/login", routing.AuthLoginPOST)
    	auth.Post("/register", routing.AuthRegisterPOST)
    	auth.Post("/reset", routing.AuthResetPOST)
    	auth.Put("/reset/confirm", routing.AuthResetConfirmPOST)
    	// - Accounts
    	accounts := apiV1.Group("/accounts")
    	accounts.Use(routing.FullAuthorizationMiddleware) // requires auth token
    	accounts.Get("/:username", routing.AccountsGET)
    

    And this is what happens: screenshot

    opened by kisulken 4
  • Authorization middleware

    Authorization middleware

    Hi, it isn't really an issue but more a question.

    I want to create a middleware which check the api key and if the api key is not valid then request does not go any further.

    For example, request is http://example.com/accounts?api_key=xxx It goes thru the middleware of /accounts group and it seems like api_key is not valid. How do I reject the request at the stage of it going thru the middleware?

    opened by kisulken 2
  • /user/100/   match  l.Get(

    /user/100/ match l.Get("/user/:id"

    http://localhost:3007/user/ 404 http://localhost:3007/user/100 right http://localhost:3007/user/100/ expect 404 but match "/user/:id"

    opened by tablecell 1
  • Fix middleware copying when creating new group

    Fix middleware copying when creating new group

    When creating new group when copying middlewares from parent router we loose some in the process. It seems that when allocating space for middlewares by mistake we allocate space for the NEW middlewares instead of the parent ones. This should fix the problem

    opened by harnash 1
  • doc: fix install command and use the right markdown flag

    doc: fix install command and use the right markdown flag

    In #11 I inverted the -u flag in the go get command, it should be go get -u not go -u get. Sorry about that.

    Also, I changed to the markdown flag from go to shell.

    opened by ericmdantas 1
  • override 404 and 405 handlers

    override 404 and 405 handlers

    Is it possible to override the 404 and 405 handlers of a route/group? Is it something you would like to have? I could submit a PR, making a NewFromOpts where you can pass the following:

    • 404 handlersChain HandlersChain
    • 405 handlersChain HandlersChain
    • redirectTrailingSlash bool
    • handleMethodNotAllowed bool
    • automaticallyHandleOPTIONS bool

    By the way: just wanted to say that I really like this router, AWESOME work! Lately I have been looking extensively into the 'router ecosystem' of Go 😉 and this is exactly what I was looking for! 👍

    question 
    opened by dvic 8
Releases(v4.0.1)
  • v4.0.1(Oct 31, 2017)

  • v4.0.0(Jun 25, 2017)

    What's changed?

    • Corrected a bug with the Group middleware see #17
    • Split out Group function for clarity into:
      • Group - retains existing middleware
      • GroupWithMore - retains existing middleware + adds more
      • GroupWithNone - groups with no middleware
    • renamed examples dir to _examples
    Source code(tar.gz)
    Source code(zip)
  • v3.7.1(Apr 19, 2017)

  • v3.7.0(Oct 14, 2016)

    What's new?

    • updated gzip middleware, now handles no content written to the response eg. browser won't download an error file when no content was written.
    • updated logging and recovery middleware to use new ansi library for colors, reducing duplicate code in multiple projects.
    Source code(tar.gz)
    Source code(zip)
  • v3.6.0(Oct 3, 2016)

  • v3.5.0(Sep 28, 2016)

  • v3.4.1(Sep 19, 2016)

    What was fixed?

    Added another context workaround for chained handlers, this is not an issue with lars but rather the assumption that context.Context() is used with chained handlers only ( an incorrect assumption at that )

    Source code(tar.gz)
    Source code(zip)
  • v3.4.0(Aug 31, 2016)

    What's New?

    • added QueryParams() url.Values function to default context for caching multiple access to http.Request.URL.Query() Values; the normal behaviour is to re-parse every time.
    Source code(tar.gz)
    Source code(zip)
  • v3.3.1(Aug 24, 2016)

    What was fixed?

    Nothing in lars was fixed, just a workaround provided to save everyone that is using an external library that stored the http.Request as a map key.

    eg. nosurf, gorilla context ..........

    boy once people start using the built in context object on the http.Request they are going to find some fun quirks, because of the way context is tied to the http.Request libraries like nosurf that store the http.Request in a map key, but as soon you store a value the http.Request changes and then the http.Request cannot be found in the map anymore in another middleware after that.

    I can just imagine the number of applications that could break because of this.... anyway the temporary workaround will save you, but if you're using a non lars.Context handler be sure to shallow copy the request to avoid this issue.

    // because 'r' is a copy of a pointer to allow the information to get
    // back to the caller, need to set the value of 'r' as below with '*r'
    func(w http.ResponseWriter, r *http.Request) {
        *r = *r.WithContext(context.WithValue(r.Context(), 0, "testval1"))
    }
    
    Source code(tar.gz)
    Source code(zip)
  • v3.3.0(Aug 24, 2016)

    What's New?

    • updated to use std lib context and new embedded http.Context new in Go 1.7 ( set it up a long time ago for this, just finally found time to implement )

    Don't worry, no breaking changes, Go 1.6 and earlier will still work as it always has.

    Special Note

    I don't know if it was an oversight or just an assumption about how middleware would be used with Go 1.7's new context integration into the *http.Request but there are a few quirks. As you know lars handles multiple handler types, including the native handler, this functionality is possible because of the way lar handles the middleware; lars does not chain the middleware in the normal way, but rather calles each in sequence; because of this all you have to do is call c.Next() or it has already been wrapped to do so for you transparently. OK getting back to the point, if you are not using lars.Context to set the context information you will have to set the request object so that the information gets back to the calling package. eg.

    // because 'r' is a copy of a pointer to allow the information to get
    // back to the caller, need to set the value of 'r' as below with '*r'
    func(w http.ResponseWriter, r *http.Request) {
        *r = *r.WithContext(context.WithValue(r.Context(), 0, "testval1"))
    }
    

    this is not an issue specific to lars, but a quirk of the way context is tied to the http.Request object.

    Source code(tar.gz)
    Source code(zip)
  • v3.2.0(Jul 8, 2016)

  • v3.1(Jun 2, 2016)

    What Changed?

    Added Decode() to the Context object for JSON, XML, FORM + Multipart FORM decoding into a struct.

    Example

    For full example see here.

    currently JSON, XML, FORM + Multipart Form's are support out of the box. Can add more by overriding the Decode method using your own Context.

        // first argument denotes yes or no I would like URL query parameter fields
        // to be included. i.e. 'id' in route '/user/:id' should it be included.
        // run, then change to false and you'll see user.ID is not populated.
        if err := c.Decode(true, maxBytes, &user); err != nil {
            log.Println(err)
        }
    
    Source code(tar.gz)
    Source code(zip)
  • v3.0(May 26, 2016)

    What's New?

    Changed Websocket implementation to "github.com/gorilla/websocket", that's it. Had to bump the version because it is a potential breaking change....

    Source code(tar.gz)
    Source code(zip)
  • v2.7(Apr 13, 2016)

    What's New?

    • Starting to do releases + notes ;)
    • Reworked golang.org/x/net/context logic ( backward compatible of course ) and added some helper methods WithCancel, WithDeadline, WithTimeout and WithValue. When Go 1.7 comes out will update backend to seamlessly use http.Request's Context.
    • Added Context() and WithContext(ctx context.Context) methods on lars's Context to get and set the context, mirroring how it will work on the Go 1.7 Request object.
    • Change how request scoped variables are stored and accessed; replaces map[string]interface with golang.org/x/net/context, which is actually a little faster and will fit right into how Go 1.7 will do it ( this way I can keep lars compatible with standard http handlers )
    Source code(tar.gz)
    Source code(zip)
Owner
Go Playgound
multiple packages, libraries and programs to further the advancement of Go!
Go Playgound
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 103 Apr 10, 2022
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 11.9k Aug 6, 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 251 May 30, 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
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

徐佳军 527 Jul 16, 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 458 Jul 29, 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 21 Apr 19, 2022
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 441 Aug 8, 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 128 Aug 8, 2022
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 17.2k Aug 14, 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 24 Aug 2, 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 54 Jul 18, 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 130 Jul 24, 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.3k Aug 8, 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 550 Aug 3, 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 105 Mar 21, 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 51 Jun 1, 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 13.5k Dec 9, 2021