justinas / alice Goto Github PK
View Code? Open in Web Editor NEWPainless middleware chaining for Go
Home Page: https://godoc.org/github.com/justinas/alice
License: MIT License
Painless middleware chaining for Go
Home Page: https://godoc.org/github.com/justinas/alice
License: MIT License
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?
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
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.
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.
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
when I install throttled, execute go get
command:
go get "github.com/throttled/throttled"
here is an error:
can't load package: package github.com/throttled/throttled: code in directory /Users/litanhua/GoglandProjects/cloudstorage/src/github.com/throttled/throttled expects import "gopkg.in/throttled/throttled.v2"
thank you!
https://github.com/stretch/testify/assert returns 404 but is required in testing, so I can't run the tests.
You said Alice make no garentees with middleware's behaviors,
it will stop the chain when panic,
so how can I make recovery as a middleware?
how is this used with gorilla mux for example?
--Update.. Got it working.. my issue was actually in my middleware.. However is there are reason for example that the Gorilla mux router can't be chained.. right now I have it as
alice.New(th.Throttle, timeoutHandler, authReq).Then(gorillaMuxRouter) to work..
if I do
alice.New(th.Throttle, timeoutHandler, authReq,gorillaMuxRouter).Then(nil)
then it won't work and I'll get a compile time error.
Why is it called Alice
?
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.
Hi,Justinas.
Nice Work,I must say !! Alice is a elegant way to implement a middleware layer.
But I also found it is diffcult to execute a middleware after the app run? Just like how the logger do in negroni.
like this:
in --> recovery --> logging --> csrf --> app
out <- logging
Do I make myself clear?
There are no more examples? request more examples available for testing.
type Constructor func(http.Handler) http.Handler
is used for defining middleware functions, and is used as part of New(constructors ...Constructor) {
this has caused some problems for me due to the lack of implicit type aliasing on sliced variadic parameters. example here: https://play.golang.org/p/5arBiRLckG
the issue i'm facing is that i'm writing a package where i'd like to users to be able to define a slice of func(http.Handler) http.Handler and not have to import alice in order to provide them. i know i can iterate and manually do the type conversion, and i'm doing that for now, but i figured i'd make this issue anyway just as something for you to consider.
Thanks
Issue
Blog post URL provided in README.md is not working and throwing 404 error.
There is a slash at the end of URL that causes this issue.
Possibly, the server has configured routes in this way thus it is expected behavior at blog (server).
Solution
Need to remove last slash from URL
How about using higher order functions by having Chain implement http.Handler?
https://gist.github.com/emrekzd/3d610cfccbdc795eb412
Additional question: why not do nothing handler?, like:
http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})
Status code is not being passed. Try returning an error:
http.Error(w, http.StatusText(401), http.StatusUnauthorized)
You will get the message but not the status code.
Thoughts on an implementation along the lines of this? I'm not a very experienced programmer, so my opinions may be invalid.
type Constructor interface {
Construct(http.Handler) http.Handler
}
type ConstructorFunc func(http.Handler) http.Handler
func (c ConstructorFunc) Construct(h http.Handler) http.Handler {
return c(h)
}
This allows a function with that signature to be casted with ConstructorFunc,
trying to follow the same idiom as http.Handler and http.HandlerFunc.
Useful things like wrapping something and giving it a Construct method would be great.
type AliceLogger struct {
*log.Logger
}
func (l *AliceLogger) Construct(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
l.Printf("Logging the %v request.", r.Method)
h.ServeHTTP(w, r)
})
}
Although this would be a breaking change, but would allow for easy addition of various kinds of middleware simply by writing a Construct method. Also I noticed that Then() would allow Alice to implement itself (although unnecessary) by changing Then() to Construct().
logger := &log.Logger{log.New(os.Stdout, "TestLogger", 0)}
alice.New(logger).Construct(nil)
Also, if it's breaking, maybe rename it to Adapter, with a method of Adapt(), based on this talk by Mat Ryer:
https://youtu.be/tIm8UkSf6RA?t=26m56s
I also implemented this in a separate branch to test it out:
https://github.com/jkearse3/alice/tree/newinterface
Thoughts or corrections to anything I proposed?
Have you guys tested using http.TimeoutHandler with alice?
How is the best way, in your opinion, to make it works?
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.
@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.
Would be very nice for those of us using package managers such as glide.
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.
Hi, I love alice and it works great alongside github.com/julienschmidt/httprouter until I need to do a per route middleware.
authChain := alice.New(
rest.CorrellationMiddleware,
rest.LogMiddleware(log),
rest.TimeoutMiddleware,
rest.JwtAuthenticationMiddleware(pubKey)
);
noAuthChain := alice.New(
rest.CorrellationMiddleware,
rest.LogMiddleware(log),
rest.TimeoutMiddleware
);
router.POST("/auth/login", noAuthChain.ThenFunc(userController.Authenticate))
router.GET("/users/me", authChain.ThenFunc(userController.Me))
This wont work since Httprouter requires a signature of (w http.ResponseWriter, r *http.Request, _ httprouter.Params)
as a handler
Is there some way to get this to work even though?
Which way of passing values between middlewares do you suggest?
In case you do not want to have a global vars (e.g.. gorilla-*) but want something specific to the request itself.
Imaging that you have middleware which extracts a lot of data from request and store then in some context struct for down the road middlewares to use this info to perform activities.
(simple example is Authentication or Session info)
e.g.: goji passes a goji.C (a context) struct down the chain.
I'm trying to create a website with httprouter
and alice
. I saw that alice has the nice option to do alice.New().Then()
and pass in the Then()
a handler to be executed. Sadly, I can only pass a handler declared as this: func myhandler(w http.ResponseWriter, r *http.Request) {
if I only wrap it in an http.HandlerFunc()
first. Why isn't possible to just pass one of those? Assuming there's a good chance that the majority of the users will be passing one of those handlers there?
Is there any way I can inject a dependency such as a *sql.DB
or something into my middleware?
I want to be able to verify session users and user roles that require access to a database. It makes sense to add this logic to the middleware, but I'm struggling to wrap my head around how it would work.
Any suggestions?
This works:
r.Get("/hello/{name}", alice.New(middleware.Junk).Then(http.HandlerFunc(HelloServer)))
chain := alice.New(middleware.Auth).Then(r)
http.ListenAndServe(":12345", chain)
For specifying route specific middleware. Is there any reason why I should not do this and also have middleware for the router? It would be useful for route specific permissions (the use case I had in mind).
How would you use this if you want to use a middle per route/path?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.