Code Monkey home page Code Monkey logo

negroni's Introduction

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 efficient 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

negroni's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

negroni's Issues

How do I convert a handler without rewriting it?

I have the following code, which is a handler who shows a Hello World in russian...

func home(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "привет, мир!")
}

... And now, I want to chain a few middlewares on top of it using gorilla/pat, before it gets executed, like this:

router := pat.New()
router.Handle("/", negroni.New(middleware1, middleware2, home)).Methods("GET")

And I have several handlers with the same signature (w http.ResponseWriter, r *http.Request). How can I convert them to be usable with Negroni without editing all of them?

This library doesn't seem to work.

My GoPath is /Developer/GOPATH

I tried to install your package:
go get -u github.com/codegangsta/negroni

The command prompt returned:

../GOPATH/src/github.com/codegangsta/negroni/negroni.go:33: method m.next.ServeHTTP is not an expression, must be called
../GOPATH/src/github.com/codegangsta/negroni/response_writer.go:82: undefined: http.CloseNotifier

Running spdy with negroni results in no spdy support.

Running spdy with negroni results in no spdy support.

Example code:

import (
  "github.com/codegangsta/negroni"
  "github.com/SlyMarbo/spdy"
  "net/http"
  "fmt"
)

mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "%f", spdy.SPDYversion(w))
})
n := negroni.New()
n.UseHandler(mux)

err := spdy.ListenAndServeTLS(":443", "cert.pem", "key.pem", n)

See also SlyMarbo/spdy#80

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 :(

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?

Order shouldn't matter + other ideas for improvement

I'm really glad this project was started, I have a few thoughts and wanted to gauge interest in taking contributions along this line of thinking. Feel free to call out if some of these ideas don't make sense

  • Calling methods in the right order shouldn't be required
  • Underlying API should build a semantic model representing the intent of the user and later should call build when starting the app (including route information), another way of looking at it is to separate the configuration from the runtime.
    • This should allow the method order to not matter anymore
    • Another handler could potentially leverage this information for diagnostics information about your application
  • Middleware shouldn't be globally applied always
    • There needs to be a way for each route to have unique middleware applied
    • The semantic model described above will also help with this
  • Although implementation doesn't require a specific router, route details should still be part of the API concerns to help facilitate objectives listed above. This can still delegate to a router adapter during startup.

I'm happy to help contribute some of these ideas and have already spiked some of them out on my own before this project was announced. I would rather not build a yet another golang middleware project and instead help contribute to one that has good potential.

Writing to ResponseWriter.Header() later

How would you go to write an header after the request as been sent. I tought this would work but indeed it doesn't since the response as been written already.

func NewResponseTime() negroni.HandlerFunc {
    return negroni.HandlerFunc(ResponseTime)
}

func ResponseTime(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
    startTime := time.Now()

    next(rw, r)

    duration:=time.Since(startTime)
    rw.Header().Add("X-Response-Time", duration.String())
    fmt.Printf("in: %q", duration.String())
}

Single handle functions for any kind of handlers

One Use function to handle all type of handlers ?

func (n *Negroni) use(handler Handler) {
    n.handlers = append(n.handlers, handler)
    n.middleware = build(n.handlers)
}

// Use adds a Handler onto the middleware stack. 
// Handlers are invoked in the order they are added to a Negroni.
func (n *Negroni) Use(handler interface{}) {
    switch handler := handler.(type) {
        case http.Handler:
            n.use(Wrap(handler))
        case Handler:
            n.use(handler)
        case func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc):
            n.use(HandlerFunc(handler))
        case func(rw http.ResponseWriter, r *http.Request):
            n.use(Wrap(http.HandlerFunc(handler)))
        default:
            panic("unknown handler")
    }
}

Add expvar support

I'd like to use the expvar package, and like other packages the router is a 'catch-all' and the /debug/vars request returns 404.

It's possible to add support for it? (like here )

Thanks.

gin: bind: address already in use

I get the following error when I try to access my negroni app using gin:

gin
[gin] listening on port 3000
[negroni] listening on :3000
[negroni] listen tcp :3000: bind: address already in use
2014/05/21 14:25:36 http: proxy error: dial tcp 127.0.0.1:3001: connection refused

thoughts on negroni contrib middleware

In the same spirit as martini contrib, I'm wondering if there is a possibility of the same for negroni. What would be really awesome would be to have a common contrib for both negroni and martini, where you would use one function to tie into martini and another for negroni. I'm using negroni in a project and modified the secure and render packages to make it work (obviously would be a bit different than using them in martini).

What are your thoughts?

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.

Typos negroni.codegangsta.io

On negroni.codegangsta.io you can find:

Negroni won't impose it's types on your code, so you can develop your app without feeling locked in to a library.

s/it's/its/; s/in to/into/

could i get a router param in middleware

Hi,
i want to check some auth in middleware, should check url param is valid. but i use mux.Vars["dbId"], it return empty. like below code,

// my app url
router1 := mux.NewRouter()
router1.HandleFunc("/hrm/{dbId}/users", handler)
mainRouter.PathPrefix("/hrm").Handler(negroni.New(
    middleware2,
    negroni.Wrap(router1),
))

// in middleare
func (m *middleware2) ServeHTTP(w http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
    vars := mux.Vars(req)

   // the dbId is empty, how to i get router param there?
    dbId := vars["dbId"]
}

how can i get router param in middleware?
thanks.

Adding HandleFunc()-style interface

This runs perilously close to an aesthetic debate, but I notice that the following does not work:

n := negroni.New()
f := func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
  ...
}
n.Use(f)

Whereas adding a typecast works:

n.Use(negroni.HandlerFunc(f))

This is because negroni's Use() takes a negroni.Handler, an interface satisfied by negroni.HandlerFunc, which is in turn equivalent to a function with f()'s signature. Golang doesn't try to resolve the equivalence automatically, which makes the explicit cast necessary.

There's a similar pattern in other HTTP handling libraries, including net/http and gorilla/mux, but those libraries offer xyz.HandleFunc() methods when you want to use plain old functions. I have no data to back this, but it feels like most straight-ahead code would use plain functions as middleware, as opposed to objects that define a middleware-style ServeHTTP().

Would folks in the negroni community be opposed to adding a HandleFunc()-style interface, to obviate the need for the cast? I can make the pull request if there's interest, but it seems like it would be about as complicated as the following:

func (n *Negroni) UseFunc(handlerFunc HandlerFunc) {
    n.Use(handlerFunc)
}

This makes the Negroni interface less orthogonal, but it would reduce verbosity in what I (somewhat blindly) suspect is the majority use-case.

Recover doesn't work sometimes

I run negroni.Classic(). But when I can't connect to the Postgres, I get this error:
"dial tcp 127.0.0.1:5432: connection refused"
and my server stops.

Middleware

I don't seem to be able to get Middleware to work (I'm new to golang).

I'm using gorilla mux.

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

func main() {
n := negroni.Classic()
router := mux.NewRouter()
router.HandleFunc("/sms/", negroni.New(Auth, PostSMS)).Methods("GET")
n.UseHandler(router)
n.Run(":3000")
}

[Question] Why does the Run func create its own logger?

Hi

Noticed that the Run function creates it's own logger instead of using the potential attached logger when creating the negroni instance.

func (n *Negroni) Run(addr string) {
    l := log.New(os.Stdout, "[negroni] ", 0)
    l.Printf("listening on %s", addr)
    l.Fatal(http.ListenAndServe(addr, n))
}

Any reason for this?

BR
Fredrik

Recovery logger to Stderr

It might be useful if the recovery logger logs to stderr, especially if one wants to separate ordinary request logs from errors with stack traces. Tools like supervisor have features to write logs into separate files based on stdout and stderr.
I know I could simply override and use my own recovery middleware but I though of suggesting a change of the default setting as of the upper reasons.

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?

UseHandler(nil) behavior inconsistent with stdlib

In the standard library, passing nil to ListenAndServe makes use of DefaultServeMux():

http.ListenAndServe(addr, nil)

Negroni UseHandler doesn't work this way:

n.UseHandler(nil)
[negroni] PANIC: runtime error: invalid memory address or nil pointer dereference

I didn't notice this was the problem right away because I had my own little convenience function much like Run that happened to be receiving a nil mux.

Anyway, not sure if this is something that needs to be fixed or documented. Just thought I'd point out the issue I ran into when first adopting Negroni. Thanks Jeremy.

NotFound handler being default and not configurable

I want to be able to chain different negroni handlers together, so I can have different middleware for different sets of paths. The problem is, negroni defaults to having a NotFound handler that gets called if the response writer wasn't written.

This prevents me from calling different negroni sets sequentially, because if the route isn't found in the first handler, a NotFound error is written. Is there a way to disable the NotFound handler? In github.com/julienschmidt/httprouter, you can provide your own (which I set to an empty function so it doesn't call it). Below is example code. /hello2 is not callable because a NotFound is sent first.

package main

import (
  "github.com/codegangsta/negroni"
  "net/http"
  "fmt"
  "log"
  "github.com/julienschmidt/httprouter"
)

type ResponseWriter struct {
  http.ResponseWriter
  written bool
}

func (r *ResponseWriter) Write(p []byte) (int, error) {
  r.written = true
  return r.ResponseWriter.Write(p)
}

func Chain(handlers ...http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
    rw := &ResponseWriter{ResponseWriter: w}
    for _, handler := range handlers {
      handler.ServeHTTP(rw, req)
      if rw.written {
        return
      }
    }
    if !rw.written {
      http.NotFound(w, req)
    }
  })
}

func main() {
  hr1 := httprouter.New()
  hr1.GET("/hello1", func(w http.ResponseWriter, req *http.Request, vars map[string]string) {
    fmt.Fprintf(w, "hello 1")
  })
  hr1.NotFound = func(w http.ResponseWriter, req *http.Request) {}

  hr2 := httprouter.New()
  hr2.GET("/hello2", func(w http.ResponseWriter, req *http.Request, vars map[string]string) {
    fmt.Fprintf(w, "hello 2")
  })
  hr2.NotFound = func(w http.ResponseWriter, req *http.Request) {}

  n1 := negroni.New()
  n1.UseHandler(hr1)

  n2 := negroni.New()
  n2.UseHandler(hr2)

  router := Chain(n1, n2)  
  log.Fatal(http.ListenAndServe(":3000", router))
}

Set status before calling beforeFuncs in response_writer.go

request status is being set after calling beforeFuncs here: https://github.com/codegangsta/negroni/blob/master/response_writer.go#L44

The thing is that if I need to write a middleware which sets some headers based on the statuscode of the request I cannot do it as beforeFuncs are executed before the status is set.

The specific scenario I was thinking of is to write a Before func which sets an "X-Response-Time" header only if request was successful (2xx). As it's today I couldn't find a way to add headers based on the status code that my handlers set.

Disable stack trace

Is there any way to disable stack trace when app is in production after a crash?

I feel it is a security concern.

how to use specific middleware for some urls

Hi,

like below 2 urls('/weixin/oauth2/refresh' and '/weixin/oauth2/userinfo'). i want to check some cerification .

but when i call '/weixin/oauth2/refresh', the server return 404 not found.

How I can to that ? thanks:)

122

Version tag

Hi! Would you mind create version tag? So we can use your awesome package through awesome gopkg.in.

pass around services

what is the best way to access services like db and render (as you have no dependency injection like in Martini)

Is it okay to just use global variables ? I have created a package called services with a global var, but not sure...

package main

import (
  "github.com/codegangsta/negroni"
  "github.com/gorilla/mux"
  "controllers"
)

func main() {

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

  n := negroni.New()
  n.UseHandler(router)

  n.Run(":3000")

}

package controllers

import (
  "net/http"
  "services"
)

func Hello(w http.ResponseWriter, req *http.Request) {
  services.Get.Renderer.HTML(w, http.StatusOK, "hello", nil)
}

package services

import (
  "github.com/unrolled/render"
)

type Services struct {
  Renderer *render.Render
}

var Get = Services{
  Renderer: render.New(render.Options{
    Directory: "templates",
  }),
};

Pass along request context to downstream middleware/controller

I really like the idea of a less magical middleware systems. I'm wondering if there's any plan to add capability to pass objects downstream to another middleware/controller, a.k.a. a request context. For example, I've a Auth middleware which authenticates users and return a User object. Is there a way to pass along this instance to downstream middleware/controller?

New Feature for Negroni

Jeremy,

If you go to this page: http://mattstauffer.co/blog/laravel-5.0-middleware-replacing-filters and go to the section titled "How do I implement before vs. after filters in middleware?" at the very bottom.

You will see that the next() returns the response that has already been sent by the handler or later middleware.

By using the response, then you can create after filters (i.e. do stuff after the next() function) which can use the response as an extra input.

I think it would be a great feature to bring Negroni in line with other framework's handling of middleware.

Also, it may be quite easy to implement.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.