MCPcopy
hub / github.com/urfave/negroni

github.com/urfave/negroni @v3.1.1 sqlite

repository ↗ · DeepWiki ↗ · release v3.1.1 ↗
147 symbols 617 edges 15 files 42 documented · 29%
README

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: * Deutsch (de_DE) * Português Brasileiro (pt_BR) * 简体中文 (zh_CN) * 繁體中文 (zh_TW) * 日本語 (ja_JP) * Français (fr_FR) * 한국어 (ko_KR)

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](h

Extension points exported contracts — how you extend this code

Handler (Interface)
Handler handler is an interface that objects can implement to be registered to serve as middleware in the Negroni middle [6 …
negroni.go
PanicFormatter (Interface)
PanicFormatter is an interface on object can implement to be able to output the stack trace [3 implementers]
recovery.go
ResponseWriter (Interface)
ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about the response. It is recomme [1 …
response_writer.go
ALogger (Interface)
ALogger interface
logger.go
HandlerFunc (FuncType)
HandlerFunc is an adapter to allow the use of ordinary functions as Negroni handlers. If f is a function with the approp
negroni.go

Core symbols most depended-on inside this repo

ServeHTTP
called by 30
negroni.go
Use
called by 24
negroni.go
New
called by 23
negroni.go
NewResponseWriter
called by 22
response_writer.go
Status
called by 16
response_writer.go
UseHandler
called by 13
negroni.go
Written
called by 11
response_writer.go
WriteHeader
called by 10
response_writer.go

Shape

Function 69
Method 52
Struct 20
Interface 4
FuncType 2

Languages

Go100%

Modules by API surface

response_writer_test.go34 symbols
negroni.go24 symbols
response_writer.go17 symbols
recovery.go12 symbols
negroni_test.go12 symbols
recovery_test.go11 symbols
logger.go9 symbols
response_writer_feature.go8 symbols
static_test.go6 symbols
response_writer_pusher_test.go4 symbols
static.go3 symbols
negroni_bench_test.go3 symbols

For agents

$ claude mcp add negroni \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact