Painless middleware chaining for Go

Overview

Alice

GoDoc Build Status Coverage

Alice provides a convenient way to chain your HTTP middleware functions and the app handler.

In short, it transforms

Middleware1(Middleware2(Middleware3(App)))

to

alice.New(Middleware1, Middleware2, Middleware3).Then(App)

Why?

None of the other middleware chaining solutions behaves exactly like Alice. Alice is as minimal as it gets: in essence, it's just a for loop that does the wrapping for you.

Check out this blog post for explanation how Alice is different from other chaining solutions.

Usage

Your middleware constructors should have the form of

func (http.Handler) http.Handler

Some middleware provide this out of the box. For ones that don't, it's trivial to write one yourself.

func myStripPrefix(h http.Handler) http.Handler {
    return http.StripPrefix("/old", h)
}

This complete example shows the full power of Alice.

package main

import (
    "net/http"
    "time"

    "github.com/throttled/throttled"
    "github.com/justinas/alice"
    "github.com/justinas/nosurf"
)

func timeoutHandler(h http.Handler) http.Handler {
    return http.TimeoutHandler(h, 1*time.Second, "timed out")
}

func myApp(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello world!"))
}

func main() {
    th := throttled.Interval(throttled.PerSec(10), 1, &throttled.VaryBy{Path: true}, 50)
    myHandler := http.HandlerFunc(myApp)

    chain := alice.New(th.Throttle, timeoutHandler, nosurf.NewPure).Then(myHandler)
    http.ListenAndServe(":8000", chain)
}

Here, the request will pass throttled first, then an http.TimeoutHandler we've set up, then nosurf and will finally reach our handler.

Note that Alice makes no guarantees for how one or another piece of middleware will behave. Once it passes the execution to the outer layer of middleware, it has no saying in whether middleware will execute the inner handlers. This is intentional behavior.

Alice works with Go 1.0 and higher.

Contributing

  1. Find an issue that bugs you / open a new one.
  2. Discuss.
  3. Branch off, commit, test.
  4. Make a pull request / attach the commits to the issue.
Comments
  • Initialize Go Modules and Tag v1.0.0 release

    Initialize Go Modules and Tag v1.0.0 release

    I realize alice had a v1.0.0 release which was removed. Now that modules support for Go is stable and adoption is growing, would it be possible to add back the v1.0.0 release tag and initialize modules for alice? Thanks for your consideration!

    Dan

    opened by gilcrest 9
  • PullRequest_AddingPowerSupport_golang-github-justinas-alice

    PullRequest_AddingPowerSupport_golang-github-justinas-alice

    Adding Power support & making the build run for both arch: amd64/ppc64le.

    Adding power support ppc64le This is part of the Ubuntu distribution for ppc64le. This helps us simplify testing later when distributions are re-building and re-releasing. For more info tag @gerrith3.

    The go versions: 1.1.x/1.2.x/1.3.x/1.4.x are not supported on Power(arch: ppc64le) and hence have been excluded from the script. The build is successful for rest all, Please refer the Travis [email protected]://travis-ci.com/github/santosh653/alice

    opened by santosh653 8
  • tag 1.0.0 was deleted without notice which caused errors with glide

    tag 1.0.0 was deleted without notice which caused errors with glide

    Hi, we've just noticed that our build jobs started failing because of the deleted tag in your repository.

    we use glide with a following configuration:

    • package: github.com/justinas/alice version: ^1.0.0

    However, with this configuration glide fails to fetch corresponding alice package To reproduce issue locally, first remove glide cache under ~/.glide/

    glide version:

    $ glide -v
    glide version v0.12.3
    
    opened by krnkl 7
  • possibility to chain a context.Context capable http handler from normal chain

    possibility to chain a context.Context capable http handler from normal chain

    Hello there, I needed this, so voila :)

    It allows you to contextualise an http request.

    In my case it's for appengine

    1/ create an handler :

    package handlers
    
    import (
        "net/http"
    
        "google.golang.org/appengine"
    
        "github.com/azr/alice"
    )
    
    func AppengineContext(next alice.ContextualizedHandler) http.Handler {
        fn := func(w http.ResponseWriter, r *http.Request) {
            next.ServeHTTPC(appengine.NewContext(r), w, r)
        }
    
        return http.HandlerFunc(fn)
    }
    

    2/ now it's contextualisable and I can do

    commonHandlers.
            Contextualize(handlers.AppengineContext).
            Extend(Auth)
    

    Auth beeing something like:

    func Auth(next alice.ContextualizedHandler) alice.ContextualizedHandler {
        fn := func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
            session, err := auth(ctx, r)
            if err != nil {
                handleSessionErrors(ctx, w, err)
                return
            }
            ctx = context.WithValue(ctx, SessionKey, session)
    
            next.ServeHTTPC(ctx, w, r)
        }
    
        return alice.ContextualizedHandlerFunc(fn)
    }
    

    I hope someday http will handle ctx !

    opened by azr 7
  • An And() method for easy extending of a stack.

    An And() method for easy extending of a stack.

    @gust1n proposed an And() method for easily returning a new stack with more middleware appended to the end of the request cycle.

    While I'm reluctant to add new methods, And() seems reasonable, as it is such an essential one. As it is now, extending the stack is a bit tricky.

    stdHandlers := []alice.Constructor{gzipHandler, ratelimitHandler,
     securityHandler, authHandler}
    indexHandlers := make([]alice.Constructor, len(stdHandlers))
    copy(indexChain, stdHandlers)
    append(indexChain, xssHandler)
    indexChain := alice.New(indexHandlers).Then(indexHandler)
    

    On that note, Remove() and others will probably never come to life (defining function equality is tricky, etc.).

    And() will probably return a new stack to prevent modifying existing stacks when extending them into new ones.

    stdStack := alice.New(M1, M2)
    extStack := stdStack.And(M3)
    // stdStack is left unmodified, with only two pieces of middleware.
    
    opened by justinas 7
  • Refactor tests to remove dependency 'github.com/stretchr/testify/assert'

    Refactor tests to remove dependency 'github.com/stretchr/testify/assert'

    To make this package not have to rely on any other third party dependencies, I refactored the tests so that https://github.com/stretchr/testify is no longer necessary and allows Alice to only require the standard library. Is this okay to merge?

    opened by jkearse3 6
  • Update README.md

    Update README.md

    Updated README.md to correctly reflect the nature of the middleware. Sequentially means that they're run in sequence, not concurrently, which is also how you describe it in your documentation as excerpted below.

    // When the request comes in, it will be passed to m1, then m2, then m3
    // and finally, the given handler
    
    opened by hallas 5
  • Conditional middlewares

    Conditional middlewares

    I though it might be a good idea to make alice be able to apply middlewares based on conditions which the Request must satisfy. For example some url paths need user authentication and some don't. It's a waste to apply the auth middleware to those as well.

    Any idea on this?

    opened by 2hamed 4
  • Reuse chain?

    Reuse chain?

    I haven't tried Alice yet, but I am curious if the example below is possible:

    stdStack := alice.New(gzipHandler, ratelimitHandler, securityHandler, authHandler)
    indexChain := stdStack.Then(indexHandler)
    resourceChain := stdStack.Then(resourceHandler)
    

    If that works, it would be nice to have it mentioned in the docs.

    opened by jhillyerd 4
  • OR-Chained middlewares

    OR-Chained middlewares

    It would be cool if alice could support chaining middlewares with or instead of executing them one after one. Currently, alice executes middlewares one after the other. The thing I have in mind would be to execute the first one in the list, if that fails execute the second one etc.

    A bit more context on the use case: We would like to use this with the chain middleware in traefik which is powered by alice. We have one site which we want to secure using ip whitelist and basic auth either one should work. If a user accesses the site not on the ip whitelist, it should need to complete the basic auth.

    I'm not sure this is the right place to ask, but I figured I'd just open an issue to get the discussion going. Maybe this is a too-specific use-case for alice and would be better suited in traefik itself.

    opened by kolaente 3
  • Gracefully handle errors

    Gracefully handle errors

    I don't like the way there are no error management. What do you think to change a little bit the code to handle errors.

    something like :

    type Constructor func(http.Handler) (http.Handler, error)
    type ErrorHandler func(http.Handler, error) http.Handler //create a new type to handle errors on Then
    

    And then on Method Then :

    func (c Chain) Then(h http.Handler, eh ErrorHandler) http.Handler {
    	if h == nil {
    		h = http.DefaultServeMux
    	}
    
    	for i := range c.constructors {
    		h, err := c.constructors[len(c.constructors)-1-i](h)
    		if err != nil && eh != nil {
    			h = eh(h, err)
                            break
    		}
    	}
    
    	return h
    }
    

    nothing else change. But it will allow people to create middlewares like :

    var ErrInvalidParameter = errors.New("invalid parameter")
    
    func Mid1(h http.Handler) (http.Handler, error) {
         //Do a lot of stuff and if there are an issue with parameter 
        return h, ErrInvalidParameter // can be another error depending on the code of course this is just an example
    }
    
    func ErrHandler(http.Handler, error) http.Handler {
    	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    		switch err {
    		        case ErrInvalidParameter:
    			       w.WriteHeader(http.StatusBadRequest)
    		        default:
    			       w.WriteHeader(http.StatusInternalServerError)
    		}
    	        
                   //Add more information if wanted
    	        w.Header().Set("Content-Type", "application/json; charset=utf-8")
    	        json.NewEncoder(w).Encode(map[string]interface{}{
    		         "error": err.Error(),
                    }
               })
    }
    
    //And somewhere on main.go
    alice.New(Mid1, Mid2, Mid3).Then(App, ErrHandler)
    
    

    What do you think ? If you agree with the concept, I can do the code and unit tests.

    opened by tkanos 3
  • Examples

    Examples

    Hello! I’m a huge fan of Alice. I use it for all of my go servers. I almost always use the same three or four middleware’s as a baseline (logging, recovery, authentication, rate limiting, etc). Would you be open to a PR adding example middleware’s that solve common problems?

    I know there’s some in the README but something like logging or conditional middlewares are a bit more verbose than a quick start.

    If this is something you think would be helpful I’d be happy to put together a PR. I just don’t know if it’d be better as complete code in an examples folder or additions to the README.

    opened by krishamoud 0
  • Added: Endware functionality

    Added: Endware functionality

    For some use cases, the server may want to perform actions after the user's request has been serviced. Examples include:

    • logging the request
    • performing maintenance on resources
    • error handling
    • auditing
    • metrics
    • anything, really

    For these purposes, I have added Endware as a solution. Endware is a http.Handler alias that allows alice users to create "after the fact" middleware in a similar way to how they create regular middleware. Endware is executed after all constructors and handlers have been invoked by Then(h)/ThenFunc(h).

    Using endware is simple: chain := alice.New(m1, m2) becomes chainWithEndware := alice.New(m1, m2).Finally(e1, e2)

    This leads the flow of chainWithEndware.Then(h) to be m1 -> m2 -> h -> e1 -> e2

    The Append() functionality has been mirrored in AppendEndware(), as well as Extend being augmented to also extend endware. AfterFuncs() and AppendEndwareFuncs() are convenience method for those not dealing with http.Handlers directly.

    This is still a WIP, just wanted to open it so you could take a look at your leisure.

    Sorry in advance if this is not the way you are supposed to contribute code

    opened by protometheus 2
  • Introducing Bob: middleware chaining for RoundTrippers

    Introducing Bob: middleware chaining for RoundTrippers

    I'd like to offer an important addition to Alice: middleware chaining for http.RoundTrippers. We love Alice and use it for chaining http.Handler middleware. At the same time, working in a router area, we feel the same strong need to be able to chain http.RoundTripper middleware pieces (client-side) declaratively.

    Fortunately, the mechanism of Alice can be easily extended to support http.RoundTripper. We thought that we would offer the PR to Alice instead of keeping it on our end. Let me know what you guys think. Thanks!

    opened by sjlee 3
  • Add ConstructorFunc / MiddlewareFunc

    Add ConstructorFunc / MiddlewareFunc

    MiddlewareFunc defines a standard signature for a http.HandlerFunc which accepts a chained http.Handler to invoke. ConstructorFunc supplies an adapter for converting a MiddlewareFunc into a Constructor. This is most useful for building middleware with bound parameters via closures.


    This change is Reviewable

    opened by jgraettinger 8
  • Provide http.HandlerFunc alternative for middleware?

    Provide http.HandlerFunc alternative for middleware?

    After playing around with alice for a bit, I was wondering, might it be a good idea to provide a Constructor alternative whose signature is func(http.HandlerFunc) http.HandlerFunc? All my middleware are just handler functions, and so I have to do http.HandlerFunc(myMiddlewareFunc) before passing them into alice. This is not a big deal, but since there is also a .ThenFunc alternative to the .Then function to pass in the final handler, I was wondering if there is a reason not to provide the same flexibility for the middleware? I am not sure though what a good name for that alternative Constructor type would be since ConstructorFunc doesn't feel right to me.

    opened by samherrmann 0
Minimalist net/http middleware for golang

interpose Interpose is a minimalist net/http middleware framework for golang. It uses http.Handler as its core unit of functionality, minimizing compl

James Pirruccello 296 Sep 27, 2022
Lightweight Middleware for net/http

MuxChain MuxChain is a small package designed to complement net/http for specifying chains of handlers. With it, you can succinctly compose layers of

Stephen Searles 209 Apr 5, 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 Sep 27, 2022
A tiny http middleware for Golang with added handlers for common needs.

rye A simple library to support http services. Currently, rye provides a middleware handler which can be used to chain http handlers together while pr

InVision 98 Sep 27, 2022
A Go middleware that stores various information about your web application (response time, status code count, etc.)

Go stats handler stats is a net/http handler in golang reporting various metrics about your web application. This middleware has been developed and re

Florent Messa 586 Jul 27, 2022
gorilla/csrf provides Cross Site Request Forgery (CSRF) prevention middleware for Go web applications & services 🔒

gorilla/csrf gorilla/csrf is a HTTP middleware library that provides cross-site request forgery (CSRF) protection. It includes: The csrf.Protect middl

Gorilla Web Toolkit 831 Sep 14, 2022
A collection of useful middleware for Go HTTP services & web applications 🛃

gorilla/handlers Package handlers is a collection of handlers (aka "HTTP middleware") for use with Go's net/http package (or any framework supporting

Gorilla Web Toolkit 1.5k Sep 18, 2022
Simple middleware to rate-limit HTTP requests.

Tollbooth This is a generic middleware to rate-limit HTTP requests. NOTE 1: This library is considered finished. NOTE 2: Major version changes are bac

Didip Kerabat 2.3k Sep 27, 2022
OpenID Connect (OIDC) http middleware for Go

Go OpenID Connect (OIDC) HTTP Middleware Introduction This is a middleware for http to make it easy to use OpenID Connect. Currently Supported framewo

Xenit AB 63 Aug 22, 2022
Go HTTP middleware to filter clients by IP

Go HTTP middleware to filter clients by IP

cristaltech 3 May 29, 2022
Chi ip banner is a chi middleware that bans some ips from your Chi http server.

Chi Ip Banner Chi ip banner is a chi middleware that bans some ips from your Chi http server. It reads a .txt file in your project's root, called bani

null 1 Jan 4, 2022
URL Rewrite middleware for gin

Url Rewrite middleware for gin Example In this exable these urls use the same route http://localhost:1234/test-me http://localhost:1234/index.php/test

Lucian I. Last 3 Sep 15, 2022
A customized middleware of DAPR.

A customized middleware of DAPR.

Gatty 1 Dec 24, 2021
Gin middleware for session.

wsession Gin middleware for session management with multi-backend support: cookie-based Redis memstore Usage Start using it Download and install it: g

null 0 Jan 9, 2022
Fiber middleware for server-timing

Server Timing This is a Fiber middleware for the [W3C Server-Timing API] based on mitchellh/go-server-timing

Vlad Fratila 0 Feb 6, 2022
A minimal framework to build web apps; with handler chaining, middleware support; and most of all standard library compliant HTTP handlers(i.e. http.HandlerFunc).

WebGo v4.1.3 WebGo is a minimalistic framework for Go to build web applications (server side) with zero 3rd party dependencies. Unlike full-fledged fr

Kamaleshwar 258 Sep 2, 2022
Git with a cup of tea, painless self-hosted git service

Gitea - Git with a cup of tea View the chinese version of this document Purpose The goal of this project is to make the easiest, fastest, and most pai

Gitea 32.4k Sep 25, 2022
Git with a cup of tea, painless self-hosted git service

Gitea - Git with a cup of tea View the chinese version of this document Purpose The goal of this project is to make the easiest, fastest, and most pai

Gitea 32.5k Sep 27, 2022
Terminal string styling for go done right, with full and painless Windows 10 support.

GChalk GChalk is a library heavily inspired by chalk, the popular Node.js terminal color library, and using go ports of supports-color and ansi-styles

Jason Walton 315 Sep 26, 2022
Gogs is a painless self-hosted Git service

Gogs - A painless self-hosted Git service 简体中文 ?? Vision The Gogs (/gɑgz/) project aims to build a simple, stable and extensible self-hosted Git servi

Gogs 40.9k Sep 21, 2022