alice

package module
v0.0.0-...-6d27a4b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 21, 2015 License: MIT Imports: 2 Imported by: 0

README

Alice

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/PuerkitoBio/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. It executes all middleware sequentially so that if a piece of middleware were to stop the chain, the request will not reach the inner handlers. This is intentional behavior.

Alice works with Go 1.0 and higher, but running tests requires at least Go 1.1.

Contributing
  1. Find an issue that bugs you / open a new one.
  2. Discuss.
  3. Branch off the develop branch, commit, test.
  4. Make a pull request / attach the commits to the issue.

Documentation

Overview

Package alice provides a convenient way to chain http handlers, together with contexts. Modified to no longer only chain handlers, but also pass the contexts like suggested by google : https://blog.golang.org/context

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CtxHandlerToHandlerFunc

func CtxHandlerToHandlerFunc(ctx context.Context, fn CtxHandler) http.HandlerFunc

Types

type Chain

type Chain struct {
	// contains filtered or unexported fields
}

Chain acts as a list of http.Handler constructors. Chain is effectively immutable: once created, it will always hold the same set of constructors in the same order.

func New

func New(constructors ...Constructor) Chain

New creates a new chain, memorizing the given list of middleware constructors. New serves no other function, constructors are only called upon a call to Then().

func (Chain) Append

func (c Chain) Append(constructors ...Constructor) Chain

Append extends a chain, adding the specified constructors as the last ones in the request flow.

Append returns a new chain, leaving the original one untouched.

stdChain := alice.New(m1, m2)
extChain := stdChain.Append(m3, m4)
// requests in stdChain go m1 -> m2
// requests in extChain go m1 -> m2 -> m3 -> m4

func (Chain) Then

func (c Chain) Then(h CtxHandler) (wrappedFinal http.Handler)

Then chains the middleware and returns the final http.Handler.

New(m1, m2, m3).Then(h)

is equivalent to:

m1(m2(m3(h)))

When the request comes in, it will be passed to m1, then m2, then m3 and finally, the given handler (assuming every middleware calls the following one).

A chain can be safely reused by calling Then() several times.

stdStack := alice.New(ratelimitHandler, csrfHandler)
indexPipe = stdStack.Then(indexHandler)
authPipe = stdStack.Then(authHandler)

Note that constructors are called on every call to Then() and thus several instances of the same middleware will be created when a chain is reused in this way. For proper middleware, this should cause no problems.

nil is not allowed for Then()

func (Chain) ThenContext

func (c Chain) ThenContext(h CtxHandler) (final CtxHandler)

Same as Then, but with CtxHandler instead of wrapped-http-Handler

func (Chain) ThenFunc

func (c Chain) ThenFunc(fn CtxHandlerFunc) http.Handler

ThenFunc works identically to Then, but takes a HandlerFunc instead of a Handler.

The following two statements are equivalent:

c.Then(http.HandlerFunc(fn))
c.ThenFunc(fn)

ThenFunc provides all the guarantees of Then.

func (Chain) ThenFuncContext

func (c Chain) ThenFuncContext(fn CtxHandlerFunc) (final CtxHandler)

Same as ThenFunc, but with CtxHandler instead of wrapped-http-Handler

type Constructor

type Constructor func(context.Context, CtxHandler) CtxHandler

A constructor for a piece of middleware, also for the final method called by .Then

type CtxHandler

type CtxHandler interface {
	ServeHTTP(context.Context, http.ResponseWriter, *http.Request)
}

type CtxHandlerFunc

type CtxHandlerFunc func(context.Context, http.ResponseWriter, *http.Request)

func (CtxHandlerFunc) ServeHTTP

func (f CtxHandlerFunc) ServeHTTP(ctx context.Context, w http.ResponseWriter, r *http.Request)

ServeHTTP calls f(ctx,w, r).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL