Idiomatic HTTP Middleware for Golang

Overview

Negroni

GoDoc Build Status codebeat codecov

Notice: This is the library formerly known as github.com/codegangsta/negroni -- Github will automatically redirect requests to this repository, but we recommend updating your references for clarity.

Negroni is an idiomatic approach to web middleware in Go. It is tiny, non-intrusive, and encourages use of net/http Handlers.

If you like the idea of Martini, but you think it contains too much magic, then Negroni is a great fit.

Language Translations:

Getting Started

After installing Go and setting up your GOPATH, create your first .go file. We'll call it server.go.

package main

import (
  "fmt"
  "net/http"

  "github.com/urfave/negroni"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Welcome to the home page!")
  })

  n := negroni.Classic() // Includes some default middlewares
  n.UseHandler(mux)

  http.ListenAndServe(":3000", n)
}

Then install the Negroni package (NOTE: >= go 1.1 is required):

go get github.com/urfave/negroni

Then run your server:

go run server.go

You will now have a Go net/http webserver running on localhost:3000.

Packaging

If you are on Debian, negroni is also available as a package that you can install via apt install golang-github-urfave-negroni-dev (at the time of writing, it is in the sid repositories).

Is Negroni a Framework?

Negroni is not a framework. It is a middleware-focused library that is designed to work directly with net/http.

Routing?

Negroni is BYOR (Bring your own Router). The Go community already has a number of great http routers available, and Negroni tries to play well with all of them by fully supporting net/http. For instance, integrating with Gorilla Mux looks like so:

router := mux.NewRouter()
router.HandleFunc("/", HomeHandler)

n := negroni.New(Middleware1, Middleware2)
// Or use a middleware with the Use() function
n.Use(Middleware3)
// router goes last
n.UseHandler(router)

http.ListenAndServe(":3001", n)

negroni.Classic()

negroni.Classic() provides some default middleware that is useful for most applications:

This makes it really easy to get started with some useful features from Negroni.

Handlers

Negroni provides a bidirectional middleware flow. This is done through the negroni.Handler interface:

type Handler interface {
  ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
}

If a middleware hasn't already written to the ResponseWriter, it should call the next http.HandlerFunc in the chain to yield to the next middleware handler. This can be used for great good:

func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
  // do some stuff before
  next(rw, r)
  // do some stuff after
}

And you can map it to the handler chain with the Use function:

n := negroni.New()
n.Use(negroni.HandlerFunc(MyMiddleware))

You can also map plain old http.Handlers:

n := negroni.New()

mux := http.NewServeMux()
// map your routes

n.UseHandler(mux)

http.ListenAndServe(":3000", n)

With()

Negroni has a convenience function called With. With takes one or more Handler instances and returns a new Negroni with the combination of the receiver's handlers and the new handlers.

// middleware we want to reuse
common := negroni.New()
common.Use(MyMiddleware1)
common.Use(MyMiddleware2)

// `specific` is a new negroni with the handlers from `common` combined with the
// the handlers passed in
specific := common.With(
	SpecificMiddleware1,
	SpecificMiddleware2
)

Run()

Negroni has a convenience function called Run. Run takes an addr string identical to http.ListenAndServe.

package main

import (
  "github.com/urfave/negroni"
)

func main() {
  n := negroni.Classic()
  n.Run(":8080")
}

If no address is provided, the PORT environment variable is used instead. If the PORT environment variable is not defined, the default address will be used. See Run for a complete description.

In general, you will want to use net/http methods and pass negroni as a Handler, as this is more flexible, e.g.:

package main

import (
  "fmt"
  "log"
  "net/http"
  "time"

  "github.com/urfave/negroni"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Welcome to the home page!")
  })

  n := negroni.Classic() // Includes some default middlewares
  n.UseHandler(mux)

  s := &http.Server{
    Addr:           ":8080",
    Handler:        n,
    ReadTimeout:    10 * time.Second,
    WriteTimeout:   10 * time.Second,
    MaxHeaderBytes: 1 << 20,
  }
  log.Fatal(s.ListenAndServe())
}

Route Specific Middleware

If you have a route group of routes that need specific middleware to be executed, you can simply create a new Negroni instance and use it as your route handler.

router := mux.NewRouter()
adminRoutes := mux.NewRouter()
// add admin routes here

// Create a new negroni for the admin middleware
router.PathPrefix("/admin").Handler(negroni.New(
  Middleware1,
  Middleware2,
  negroni.Wrap(adminRoutes),
))

If you are using Gorilla Mux, here is an example using a subrouter:

router := mux.NewRouter()
subRouter := mux.NewRouter().PathPrefix("/subpath").Subrouter().StrictSlash(true)
subRouter.HandleFunc("/", someSubpathHandler) // "/subpath/"
subRouter.HandleFunc("/:id", someSubpathHandler) // "/subpath/:id"

// "/subpath" is necessary to ensure the subRouter and main router linkup
router.PathPrefix("/subpath").Handler(negroni.New(
  Middleware1,
  Middleware2,
  negroni.Wrap(subRouter),
))

With() can be used to eliminate redundancy for middlewares shared across routes.

router := mux.NewRouter()
apiRoutes := mux.NewRouter()
// add api routes here
webRoutes := mux.NewRouter()
// add web routes here

// create common middleware to be shared across routes
common := negroni.New(
	Middleware1,
	Middleware2,
)

// create a new negroni for the api middleware
// using the common middleware as a base
router.PathPrefix("/api").Handler(common.With(
  APIMiddleware1,
  negroni.Wrap(apiRoutes),
))
// create a new negroni for the web middleware
// using the common middleware as a base
router.PathPrefix("/web").Handler(common.With(
  WebMiddleware1,
  negroni.Wrap(webRoutes),
))

Bundled Middleware

Static

This middleware will serve files on the filesystem. If the files do not exist, it proxies the request to the next middleware. If you want the requests for non-existent files to return a 404 File Not Found to the user you should look at using http.FileServer as a handler.

Example:

package main

import (
  "fmt"
  "net/http"

  "github.com/urfave/negroni"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Welcome to the home page!")
  })

  // Example of using a http.FileServer if you want "server-like" rather than "middleware" behavior
  // mux.Handle("/public", http.FileServer(http.Dir("/home/public")))

  n := negroni.New()
  n.Use(negroni.NewStatic(http.Dir("/tmp")))
  n.UseHandler(mux)

  http.ListenAndServe(":3002", n)
}

Will serve files from the /tmp directory first, but proxy calls to the next handler if the request does not match a file on the filesystem.

Recovery

This middleware catches panics and responds with a 500 response code. If any other middleware has written a response code or body, this middleware will fail to properly send a 500 to the client, as the client has already received the HTTP response code. Additionally, an PanicHandlerFunc can be attached to report 500's to an error reporting service such as Sentry or Airbrake.

Example:

package main

import (
  "net/http"

  "github.com/urfave/negroni"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    panic("oh no")
  })

  n := negroni.New()
  n.Use(negroni.NewRecovery())
  n.UseHandler(mux)

  http.ListenAndServe(":3003", n)
}

Will return a 500 Internal Server Error to each request. It will also log the stack traces as well as print the stack trace to the requester if PrintStack is set to true (the default).

Example with error handler:

package main

import (
  "net/http"

  "github.com/urfave/negroni"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    panic("oh no")
  })

  n := negroni.New()
  recovery := negroni.NewRecovery()
  recovery.PanicHandlerFunc = reportToSentry
  n.Use(recovery)
  n.UseHandler(mux)

  http.ListenAndServe(":3003", n)
}

func reportToSentry(info *negroni.PanicInformation) {
    // write code here to report error to Sentry
}

The middleware simply output the informations on STDOUT by default. You can customize the output process by using the SetFormatter() function.

You can use also the HTMLPanicFormatter to display a pretty HTML when a crash occurs.

package main

import (
  "net/http"

  "github.com/urfave/negroni"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    panic("oh no")
  })

  n := negroni.New()
  recovery := negroni.NewRecovery()
  recovery.Formatter = &negroni.HTMLPanicFormatter{}
  n.Use(recovery)
  n.UseHandler(mux)

  http.ListenAndServe(":3003", n)
}

Logger

This middleware logs each incoming request and response.

Example:

package main

import (
  "fmt"
  "net/http"

  "github.com/urfave/negroni"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Welcome to the home page!")
  })

  n := negroni.New()
  n.Use(negroni.NewLogger())
  n.UseHandler(mux)

  http.ListenAndServe(":3004", n)
}

Will print a log similar to:

[negroni] 2017-10-04T14:56:25+02:00 | 200 |      378µs | localhost:3004 | GET /

on each request.

You can also set your own log format by calling the SetFormat function. The format is a template string with fields as mentioned in the LoggerEntry struct. So, as an example -

l.SetFormat("[{{.Status}} {{.Duration}}] - {{.Request.UserAgent}}")

will show something like - [200 18.263µs] - Go-User-Agent/1.1

Third Party Middleware

Here is a current list of Negroni compatible middlware. Feel free to put up a PR linking your middleware if you have built one:

Middleware Author Description
authz Yang Luo ACL, RBAC, ABAC Authorization middlware based on Casbin
binding Matt Holt Data binding from HTTP requests into structs
cloudwatch Colin Steele AWS cloudwatch metrics middleware
cors Olivier Poitrey Cross Origin Resource Sharing (CORS) support
csp Awake Networks Content Security Policy (CSP) support
delay Jeff Martinez Add delays/latency to endpoints. Useful when testing effects of high latency
New Relic Go Agent Yadvendar Champawat Official New Relic Go Agent (currently in beta)
gorelic Jingwen Owen Ou New Relic agent for Go runtime
Graceful Tyler Bunnell Graceful HTTP Shutdown
gzip phyber GZIP response compression
JWT Middleware Auth0 Middleware checks for a JWT on the Authorization header on incoming requests and decodes it
JWT Middleware Marcelo Fuentes JWT middleware for golang
logrus Dan Buch Logrus-based logger
oauth2 David Bochenski oAuth2 middleware
onthefly Alexander Rødseth Generate TinySVG, HTML and CSS on the fly
permissions2 Alexander Rødseth Cookies, users and permissions
prometheus Rene Zbinden Easily create metrics endpoint for the prometheus instrumentation tool
prometheus Xabier Larrakoetxea Prometheus metrics with multiple options that follow standards and try to be measured in a efficent way
render Cory Jacobsen Render JSON, XML and HTML templates
RestGate Prasanga Siripala Secure authentication for REST API endpoints
secure Cory Jacobsen Middleware that implements a few quick security wins
sessions David Bochenski Session Management
stats Florent Messa Store information about your web application (response time, etc.)
VanGoH Taylor Wrobel Configurable AWS-Style HMAC authentication middleware
xrequestid Andrea Franz Middleware that assigns a random X-Request-Id header to each request
mgo session Joel James Middleware that handles creating and closing mgo sessions per request
digits Bilal Amarni Middleware that handles Twitter Digits authentication
stats Chirag Gupta Middleware that manages qps and latency stats for your endpoints and asynchronously flushes them to influx db
Chaos Marc Falzon Middleware for injecting chaotic behavior into application in a programmatic way

Examples

Alexander Rødseth created mooseware, a skeleton for writing a Negroni middleware handler.

Prasanga Siripala created an effective skeleton structure for web-based Go/Negroni projects: Go-Skeleton

Live code reload?

gin and fresh both live reload negroni apps.

Essential Reading for Beginners of Go & Negroni

About

Negroni is obsessively designed by none other than the Code Gangsta

Comments
  • Add support for Google context

    Add support for Google context

    Are you thinking of updating negroni (I.e. v2) to utilize Google context.

    That seems to be idiomatic now. Everyone seems to using it. Or should I attempt to create a fork?

    http://godoc.org/golang.org/x/net/context

    https://blog.golang.org/context

    enhancement 
    opened by pjebs 22
  • Use specific middleware for specific routes

    Use specific middleware for specific routes

    What is the easiest way to specify a middleware (auth for example) for a group of routes and another middleware (or none) for another group of routes in the same app?

    opened by jamiefoster 17
  • context values cleared after handler

    context values cleared after handler

    Hi all, I'm using Negroni together with gorilla mux router (updated to the latest version).

    What I'm seeing is that the values in the request's context (using the new builtin context package) are cleared after the handler execution. I've also checked gorilla's documentation and I've updated to the latest version (they're now using the native context if Go 1.7 is used to build the program).

    In particular, inside the voidMiddleware function, the last call to it doesn't have the context values se (it appears to me that the latest version of gorilla doesn't do anything and don't clear that values)

    How can I solve?

    Thanks, Alessio

    Example code:

    package main
    
    import (
    	"context"
    	"fmt"
    	"log"
    	"net/http"
    
    	"github.com/urfave/negroni"
    )
    
    func main() {
    	mux := http.NewServeMux()
    	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    		r = r.WithContext(context.WithValue(r.Context(), "userId", 100))
    		log.Printf("___userID in handler: %v", r.Context().Value("userId"))
    		fmt.Fprintf(w, "Welcome to the home page!")
    	})
    
    	n := negroni.Classic()
    	n.Use(negroni.HandlerFunc(MyMiddleware))
    	n.UseHandler(mux)
    
    	http.ListenAndServe(":3000", n)
    }
    
    func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
    	next(rw, r)
    	log.Printf("___userID after handler: %v", r.Context().Value("userId"))
    }
    
    opened by alecha 14
  • Recovery middleware

    Recovery middleware

    I noticed that relatively recently the recovery middleware got added: ErrorHandlerFunc func(interface{}).

    If rec.ErrorHandlerFunc(err) panics, then recovery middleware will be useless because it is itself inside the recover()

    opened by pjebs 12
  • Passing references through middleware

    Passing references through middleware

    I have created a middleware called "Auth" which checks the key and secret in the REST request headers. It compares it with a database record.

    The actual endpoint handler also needs to reopen the database which is a waste. Is there a way to pass the reference through the middleware so that the endpoint handler can use it?

    opened by pjebs 12
  • Recover panics thrown by the Recovery handler ErrorHandlerFunc

    Recover panics thrown by the Recovery handler ErrorHandlerFunc

    If the user specified function itself panic's, catch and log.

    (also adds a check to the happy path test to make sure the handler was called)

    See discussion in #134.

    cc/ @pjebs

    @meatballhat I'm curious if you have any thoughts about the discussion in #134 and this implementation.

    opened by jszwedko 10
  • About Route Specific Middleware

    About Route Specific Middleware

    //front web
    router := mux.NewRouter()
    router.HandleFunc("/", controller.Index)
    
    //backend
    adminRoutes := mux.NewRouter()
    adminRoutes.HandleFunc("/admin/index", admin.Index)
    adminRoutes.HandleFunc("/admin/article", admin.Article)
    
    router.Handle("/admin", negroni.New(
      negroni.NewLogger(),
      negroni.NewStatic(http.Dir(".")),
      negroni.NewRecovery(),
      negroni.Wrap(adminRoutes),
    ))
    
    n.UseHandler(router)
    

    Why the backend (eg: http://localhost:3000/admin/index , http://localhost:3000/admin/article) appeared in 404, but the front web (eg: http://localhost:3000/) is correct.

    question 
    opened by panjunjie 9
  • Negroni does not share context accros diff middlewares properly

    Negroni does not share context accros diff middlewares properly

    I'm not sure if I'm missing something, but I'm not able to use context to pass context through my middlewares:

    Server:

    func NewApiServer() (*ApiServer, error) {
        a := &ApiServer{}
        a.n = negroni.New(negroni.NewRecovery(), negroni.HandlerFunc(errorHandlerMiddleware))
        a.drawRoutes()
        return a, nil
    }
    
    func (a *ApiServer) drawRoutes() {
        a.mux = mux.NewRouter()
        a.muxAuth = mux.NewRouter()
    
        a.mux.HandleFunc("/debug/helloworld", HelloWorldHandler)
        a.muxAuth.Handle("/services", &ServiceHandler{}).Methods("POST")
        a.mux.PathPrefix("/").Handler(negroni.New(negroni.HandlerFunc(authorizationMiddleware), negroni.Wrap(a.muxAuth)))
        a.n.UseHandler(a.mux)
    }
    

    Middlewares:

    func authorizationMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
        context.Set(r, "key", "unauthorizedRequest")
        val := context.Get(r, "key")
        log.Print(val.(string)) // It works here!
        return
    }
    
    func errorHandlerMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
        next(w, r)
    
        val := context.GetAll(r)
        log.Print(len(val)) // 0!
    }
    

    Just did another couple of tests:

    Still "0" elements:

    func errorHandlerMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
        context.Set(r, "key", "unauthorizedRequest")
        next(w, r)
    
        val := context.GetAll(r)
        log.Print(len(val))
    }
    

    "1" element in the slice:

    func errorHandlerMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
        next(w, r)
        context.Set(r, "key", "unauthorizedRequest")
        val := context.GetAll(r)
        log.Print(len(val))
    }
    

    It seems that the request is being somehow "recreated" (?)

    The error happens because of this line:

    a.mux.PathPrefix("/").Handler(negroni.New(negroni.HandlerFunc(authorizationMiddleware), negroni.Wrap(a.muxAuth)))
    

    If I use the middleware like this:

        a.n = negroni.New(negroni.NewRecovery(),
            negroni.HandlerFunc(errorHandlerMiddleware),
            negroni.HandlerFunc(authorizationMiddleware))
    

    then it works. But I need to use the authorization middleware just for some routes :(

    opened by albertoleal 9
  • Make the logger more verbose.

    Make the logger more verbose.

    Format the output of the logger with more elements. Largely inspired by gin.

    (added by @meatballhat:)

    before

    [negroni] Started GET /
    [negroni] Completed 200 OK in 159.388µs
    

    after

    [negroni] 2016-12-21T12:05:50-05:00 | 200 |      224.025µs | localhost:3000 | GET /
    
    enhancement 
    opened by yageek 8
  • MVC

    MVC

    Hi Codegangsta,

    This is just a polite request. Is there any way you could write in the readme how to arrange a golang project using Negroni in a manner that is as close as possible to a MVC arrangement?

    opened by pjebs 8
  • interface conversion: *negroni.responseWriterCloseNotifer is not negroni.ResponseWrite

    interface conversion: *negroni.responseWriterCloseNotifer is not negroni.ResponseWrite

    Hi

    Im using go version 1.7.4 on mac os

    Im am getting following error

    2016/12/02 19:32:22 http: panic serving [::1]:59323: interface conversion: *negroni.responseWriterCloseNotifer is not negroni.ResponseWriter: missing method Before
    goroutine 34 [running]:
    net/http.(*conn).serve.func1(0xc82010c000)
    	/usr/local/Cellar/go/1.6.2/libexec/src/net/http/server.go:1389 +0xc1
    panic(0x387e00, 0xc8201042c0)
    	/usr/local/Cellar/go/1.6.2/libexec/src/runtime/panic.go:443 +0x4e9
    github.com/meatballhat/negroni-logrus.(*Middleware).ServeHTTP(0xc82009c360, 0x1180248, 0xc82010a008, 0xc820124000, 0xc8201161a0)
    	/Users/go_workspace/usher/vendor/src/github.com/meatballhat/negroni-logrus/middleware.go:138 +0x61c
    github.com/codegangsta/negroni.middleware.ServeHTTP(0x1144710, 0xc82009c360, 0xc820116140, 0x1180248, 0xc82010a008, 0xc820124000)
    	/Users/go_workspace/usher/vendor/src/github.com/codegangsta/negroni/negroni.go:33 +0xaa
    github.com/codegangsta/negroni.(*Negroni).ServeHTTP(0xc820108150, 0x1180160, 0xc820128000, 0xc820124000)
    	/Users/go_workspace/usher/vendor/src/github.com/codegangsta/negroni/negroni.go:73 +0x1a6
    github.com/carbocation/interpose/adaptors.FromNegroni.func1.1(0x1180160, 0xc820128000, 0xc820124000)
    	/Users/go_workspace/usher/vendor/src/github.com/carbocation/interpose/adaptors/negroni.go:15 +0x3e
    net/http.HandlerFunc.ServeHTTP(0xc820118070, 0x1180160, 0xc820128000, 0xc820124000)
    	/usr/local/Cellar/go/1.6.2/libexec/src/net/http/server.go:1618 +0x3a
    github.com/carbocation/interpose.(*Middleware).ServeHTTP(0xc8200d4820, 0x1180160, 0xc820128000, 0xc820124000)
    	/Users/go_workspace/usher/vendor/src/github.com/carbocation/interpose/interpose.go:85 +0x6c
    net/http.serverHandler.ServeHTTP(0xc82007e180, 0x1180160, 0xc820128000, 0xc820124000)
    	/usr/local/Cellar/go/1.6.2/libexec/src/net/http/server.go:2081 +0x19e
    net/http.(*conn).serve(0xc82010c000)
    	/usr/local/Cellar/go/1.6.2/libexec/src/net/http/server.go:1472 +0xf2e
    created by net/http.(*Server).Serve
    	/usr/local/Cellar/go/1.6.2/libexec/src/net/http/server.go:2137 +0x44e
    
    opened by mg03 7
  • v3 `ResponseWriter.Before()` functions can't overwrite HTTP response code

    v3 `ResponseWriter.Before()` functions can't overwrite HTTP response code

    Heya! Starting with v3, it appears it's impossible for a (negroni.ResponseWriter).Before() callback to change the HTTP status code in a response. As a contrived example:

    package main
    
    import (
    	"fmt"
    	"net/http"
    
    	"github.com/urfave/negroni/v3"
    )
    
    func main() {
    	fiveFiveFive := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    		w.WriteHeader(555)
    	})
    
    	mux := http.DefaultServeMux
    	mux.Handle("/555", fiveFiveFive)
    	mux.Handle("/200", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    		nw := negroni.NewResponseWriter(w)
    
    		nw.Before(func(nw negroni.ResponseWriter) {
    			if nw.Status() != http.StatusOK {
    				nw.WriteHeader(http.StatusOK)
    			}
    		})
    
    		fiveFiveFive.ServeHTTP(nw, r)
    	}))
    
    	fmt.Println("listening on http://localhost:55123")
    	if err := http.ListenAndServe("localhost:55123", nil); err != nil {
    		fmt.Printf("ERROR: unable to start listening on http://localhost:55123: %+v\n", err)
    	}
    }
    

    Under v1 and v2, curl --include http://localhost:55123/200 would return HTTP 200, but under v3 it returns HTTP 555.

    From what I can tell, this was possible in v1 and v2 (but with a http: superfluous response.WriteHeader call from github.com/urfave/negroni/v3.(*responseWriter).WriteHeader error printed) due to the fact that callBefore() happens before the wrapped rw.ResponseWriter.WriteHeader(...), but the early return in rw.WriteHeader (introduced in https://github.com/urfave/negroni/pull/262) prevents a WriteHeader from within the Before() from actually writing anything to the wrapped http.ResponseWriter.

    I've got a patch working locally, so I'll put up a PR once I get some tests written for it :)

    opened by sjbarag 0
  • bug: recovery middleware has a bug

    bug: recovery middleware has a bug

    There is a comment here regarding https://github.com/urfave/negroni/blob/master/recovery.go#L160:

    https://github.com/maruel/panicparse/issues/81#issuecomment-1284620756

    As a matter of fact, the code you pointed to in recovery.go is functionally wrong. The only way it could be done is if it were buffering a temporary http.ResponseWriter, and only flushing it when the handler returned. The current code will fail at line 161 as WriteHeader() will ignore the status if data was already written (that's how HTTP works) and the stack data will just be appended to whatever was already streamed to the user. That's bad.

    bug 
    opened by pjebs 0
  • Change Logger Output

    Change Logger Output

    Hello, is there a way to change log output? I want to log into file, not stdout.

    I think it should be nice to have a helper functin at logger something like:

    func (l *Logger) SetOutput(out io.Writer) { l.output = out }

    opened by yakuter 0
  • Negroni and new relic

    Negroni and new relic

    Newrelic provides integrations with several go routers. Alas Negroni is not one. So I'm trying create one.

    However, one thing they do is wrap the ResponseWriter in the middleware. I attempted that in Negroni just like it done in several of their other integrations. However, Negroni does not like that at all and blows up!

    I don't suppose there is a way for Negroni to not wrap response writer? I'm at a loss as to what I should do. Any ideas?

    opened by rayjlinden 1
  • PANIC: runtime error: invalid memory address or nil pointer dereference

    PANIC: runtime error: invalid memory address or nil pointer dereference

    I have a server that serves a dist/ folder on a GET '/' request. But Negroni panics on any and all POST, PUT, PATCH, or DELETE requests.

    I know this might not be negronis fault, But running this on a docker instance on my local machine works like a charm, while running on a server will return this

    PANIC: runtime error: invalid memory address or nil pointer dereference goroutine 338 [running]: github.com/codegangsta/negroni.(*Recovery).ServeHTTP.func1(0x7fb434153028, 0xc00031ef00, 0xc0001100a0) /home/user/go/src/github.com/codegangsta/negroni/recovery.go:34 +0xe8 panic(0x6de540, 0x99fc40) /usr/local/go/src/runtime/panic.go:522 +0x1b5 github.com/direcotry/directory2/models.(*Pdb).Message(0x9aa960, 0xc0002b3a40, 0x8, 0x2, 0x2, 0x11, 0x0, 0x0, 0xc000099648) /home/user/go/src/github.com/direcotry/directory2/models/models.go:53 +0xa4 github.com/dvlcdr/directory2/models.Message(0xc0002b3a40, 0x8, 0x3, 0x73804e, 0x1, 0x738284, 0x4, 0xc0002b3a40) /home/user/go/src/github.com/direcotry/directory2/models/models.go:84 +0xd0 github.com/direcotry/directory2/controllers.FetchAllDb(0x7fb434153028, 0xc00031ef00, 0xc000364d00, 0x0, 0x0, 0x0) /home/user/go/src/github.com/direcotry/directory2/controllers/controllers.go:122 +0xef github.com/julienschmidt/httprouter.(*Router).ServeHTTP(0xc000122000, 0x7fb434153028, 0xc00031ef00, 0xc000364d00) /home/user/go/src/github.com/julienschmidt/httprouter/router.go:299 +0x6e0 github.com/codegangsta/negroni.Wrap.func1(0x7fb434153028, 0xc00031ef00, 0xc000364d00, 0xc000319840) /home/user/go/src/github.com/codegangsta/negroni/negroni.go:41 +0x4d github.com/codegangsta/negroni.HandlerFunc.ServeHTTP(0xc0001101e0, 0x7fb434153028, 0xc00031ef00, 0xc000364d00, 0xc000319840) /home/user/go/src/github.com/codegangsta/negroni/negroni.go:24 +0x4e github.com/codegangsta/negroni.middleware.ServeHTTP(0x79f180, 0xc0001101e0, 0xc000110280, 0x7fb434153028, 0xc00031ef00, 0xc000364d00) /home/user/go/src/github.com/codegangsta/negroni/negroni.go:33 +0x9c github.com/rs/cors.(*Cors).ServeHTTP(0xc000126000, 0x7fb434153028, 0xc00031ef00, 0xc000364d00, 0xc000319820) /home/user/go/src/github.com/rs/cors/cors.go:252 +0x190 github.com/codegangsta/negroni.middleware.ServeHTTP(0x79e780, 0xc000126000, 0xc000110260, 0x7fb434153028, 0xc00031ef00, 0xc000364d00) /home/user/go/src/github.com/codegangsta/negroni/negroni.go:33 +0x9c github.com/codegangsta/negroni.(*Static).ServeHTTP(0xc00011c090, 0x7fb434153028, 0xc00031ef00, 0xc000364d00, 0xc000319800) /home/user/go/src/github.com/codegangsta/negroni/static.go:30 +0x78d github.com/codegangsta/negroni.middleware.ServeHTTP(0x79e740, 0xc00011c090, 0xc000110240, 0x7fb434153028, 0xc00031ef00, 0xc000364d00) /home/user/go/src/github.com/codegangsta/negroni/negroni.go:33 +0x9c github.com/codegangsta/negroni.(*Logger).ServeHTTP(0xc000112098, 0x7fb434153028, 0xc00031ef00, 0xc000364d00, 0xc0003197e0) /home/user/go/src/github.com/codegangsta/negroni/logger.go:27 +0x15c github.com/codegangsta/negroni.middleware.ServeHTTP(0x79e6e0, 0xc000112098, 0xc000110220, 0x7fb434153028, 0xc00031ef00, 0xc000364d00) /home/user/go/src/github.com/codegangsta/negroni/negroni.go:33 +0x9c github.com/codegangsta/negroni.(*Recovery).ServeHTTP(0xc0001100a0, 0x7fb434153028, 0xc00031ef00, 0xc000364d00, 0xc0003197c0) /home/user/go/src/github.com/codegangsta/negroni/recovery.go:45 +0x82 github.com/codegangsta/negroni.middleware.ServeHTTP(0x79e720, 0xc0001100a0, 0xc000110200, 0x7fb434153028, 0xc00031ef00, 0xc000364d00) /home/user/go/src/github.com/codegangsta/negroni/negroni.go:33 +0x9c github.com/codegangsta/negroni.(*Negroni).ServeHTTP(0xc00011c0f0, 0x7a43a0, 0xc00035ca80, 0xc000364d00) /home/user/go/src/github.com/codegangsta/negroni/negroni.go:73 +0xdd net/http.serverHandler.ServeHTTP(0xc0001240d0, 0x7a43a0, 0xc00035ca80, 0xc000364d00) /usr/local/go/src/net/http/server.go:2774 +0xa8 net/http.(*conn).serve(0xc0002a9220, 0x7a4a60, 0xc0001ce100) /usr/local/go/src/net/http/server.go:1878 +0x851 created by net/http.(*Server).Serve /usr/local/go/src/net/http/server.go:2884 +0x2f4

    Is there any chance this could be happening from a lack of memory? Or could anyone point me in a good direction to figuring out the problem?

    question 
    opened by CarterScadden 1
Releases(v1.0.0)
  • v1.0.0(Sep 2, 2018)

  • v0.3.0(Sep 2, 2018)

    Added

    • With() helper for building a new Negroni struct chaining handlers from existing Negroni structs
    • Format log output in Logger middleware via a configurable text/template string injectable via .SetFormat. Added LoggerDefaultFormat and LoggerDefaultDateFormat to configure the default template and date format used by the Logger middleware.
    • Support for HTTP/2 pusher support via http.Pusher interface for Go 1.8+.
    • WrapFunc to convert http.HandlerFunc into a negroni.Handler
    • Formatter field added to Recovery middleware to allow configuring how panics are output. Default of TextFormatter (how it was output in 0.2.0) used. HTMLPanicFormatter also added to allow easy outputing of panics as HTML.

    Fixed

    • Written() correct returns false if no response header has been written
    • Only implement http.CloseNotifier with the negroni.ResponseWriter if the underlying http.ResponseWriter implements it (previously would always implement it and panic if the underlying http.ResponseWriter did not.

    Changed

    • Set default status to 0 in the case that no handler writes status -- was previously 200 (in 0.2.0, before that it was 0 so this reestablishes that behavior)
    • Catch panics thrown by callbacks provided to the Recovery handler
    • Recovery middleware will set text/plain content-type if none is set
    • ALogger interface to allow custom logger outputs to be used with the Logger middleware. Changes embeded field in negroni.Logger from Logger to ALogger.
    • Default Logger middleware output changed to be more structure and verbose (also now configurable, see Added)
    • Automatically bind to port specified in $PORT in .Run() if an address is not passed in. Fall back to binding to :8080 if no address specified (configuable via DefaultAddress).
    • PanicHandlerFunc added to Recovery middleware to enhance custom handling of panics by providing additional information to the handler including the stack and the http.Request. Recovery.ErrorHandlerFunc was also added, but deprecated in favor of the new PanicHandlerFunc.
    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(May 10, 2016)

    Added

    • Support for variadic handlers in New()
    • Added Negroni.Handlers() to fetch all of the handlers for a given chain
    • Allowed size in Recovery handler was bumped to 8k
    • Negroni.UseFunc to push another handler onto the chain

    Changed

    • Set the status before calling beforeFuncs so the information is available to them
    • Set default status to 200 in the case that no handler writes status -- was previously 0
    • Panic if nil handler is given to negroni.Use
    Source code(tar.gz)
    Source code(zip)
Owner
I love you so very much.
null
Go http middleware handler for request coalescing

HTTP Coala NOTE: a new and improved implementation is available at https://github.com/go-chi/stampede Just a little bit of performance enhancing middl

go-chi 128 Apr 3, 2022
Dead simple rate limit middleware for Go.

Limiter Dead simple rate limit middleware for Go. Simple API "Store" approach for backend Redis support (but not tied too) Middlewares: HTTP, FastHTTP

Ulule 1.7k Nov 29, 2022
Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.

Gin Web Framework Gin is a web framework written in Go (Golang). It features a martini-like API with performance that is up to 40 times faster thanks

Gin-Gonic 64.8k Dec 1, 2022
A lightweight and fast http router from outer space

Alien Alien is a lightweight http router( multiplexer) for Go( Golang ), made for humans who don't like magic. Documentation docs Features fast ( see

Geofrey Ernest 123 Nov 13, 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.7k Dec 8, 2022
Simple HTTP and REST client library for Go

Resty Simple HTTP and REST client library for Go (inspired by Ruby rest-client) Features section describes in detail about Resty capabilities Resty Co

Go Resty 7.1k Dec 7, 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 Sep 27, 2022
Eudore is the core of a golang lightweight web framework.

Eudore eudore是一个golang轻量级web框架核心,可以轻松扩展成一个技术栈专用框架,具有完整框架设计体系。 反馈和交流请加群组:QQ群373278915。 Features 易扩展:主要设计目标、核心全部解耦,接口即为逻辑。 简单:对象语义明确,框架代码量少复杂度低,无依赖库。 易用

null 73 Nov 7, 2022
a golang web mvc framework, like asp.net mvc.

goku goku is a Web Mvc Framework for golang, mostly like ASP.NET MVC. doc & api Installation To install goku, simply run go get github.com/QLeelulu/go

QLeelulu 273 Oct 5, 2022
🍐 Elegant Golang REST API Framework

An Elegant Golang Web Framework Goyave is a progressive and accessible web application framework focused on REST APIs, aimed at making backend develop

SystemGlitch 1.2k Nov 27, 2022
Fast and Reliable Golang Web Framework

Gramework The Good Framework Gramework long-term testing stand metrics screenshot made with Gramework Stats Dashboard and metrics middleware What is i

null 372 Dec 1, 2022
The web framework for Golang

uAdmin the Golang Web Framework Easy to use, blazing fast and secure. Originally open source by IntegrityNet Solutions and Services For Documentation:

uADMIN 217 Nov 23, 2022
A lightweight MVC framework for Go(Golang)

utron utron is a lightweight MVC framework in Go (Golang) for building fast, scalable and robust database-driven web applications. Features Postgres,

Geofrey Ernest 2.2k Nov 26, 2022
Go (Golang) Clean Architecture based on Reading Uncle Bob's Clean Architecture

go-clean-arch Changelog v1: checkout to the v1 branch Proposed on 2017, archived to v1 branch on 2018 Desc: Initial proposal by me. The story can be r

Iman Tumorang 6.9k Nov 30, 2022
Golang CTF framework and exploit development module

Golang CTF framework and exploit development module

Frank Hübner 15 Oct 2, 2022
Idiomatic HTTP Middleware for Golang

Negroni Notice: This is the library formerly known as github.com/codegangsta/negroni -- Github will automatically redirect requests to this repository

null 7.3k Nov 28, 2022
Gin-errorhandling - Gin Error Handling Middleware is a middleware for the popular Gin framework

Gin Error Handling Middleware Gin Error Handling Middleware is a middleware for

Joseph Woodward 9 Sep 19, 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 12.7k Dec 4, 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 12.7k Dec 4, 2022
⚡ Rux is an simple and fast web framework. support middleware, compatible http.Handler interface. 简单且快速的 Go web 框架,支持中间件,兼容 http.Handler 接口

Rux Simple and fast web framework for build golang HTTP applications. NOTICE: v1.3.x is not fully compatible with v1.2.x version Fast route match, sup

Gookit 84 Dec 8, 2022