{"action":"created","issue":{"url":"https://api.github.com/repos/manyminds/api2go/issues/158","labels_url":"https://api.github.com/repos/manyminds/api2go/issues/158/labels{/name}","comments_url":"https://api.github.com/repos/manyminds/api2go/issues/158/comments","events_url":"https://api.github.com/repos/manyminds/api2go/issues/158/events","html_url":"https://github.com/manyminds/api2go/issues/158","id":101408380,"number":158,"title":"Convert existing httprouter and middleware handlers to api2go: suggestions?","user":{"login":"trapias","id":2881610,"avatar_url":"https://avatars.githubusercontent.com/u/2881610?v=3","gravatar_id":"","url":"https://api.github.com/users/trapias","html_url":"https://github.com/trapias","followers_url":"https://api.github.com/users/trapias/followers","following_url":"https://api.github.com/users/trapias/following{/other_user}","gists_url":"https://api.github.com/users/trapias/gists{/gist_id}","starred_url":"https://api.github.com/users/trapias/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/trapias/subscriptions","organizations_url":"https://api.github.com/users/trapias/orgs","repos_url":"https://api.github.com/users/trapias/repos","events_url":"https://api.github.com/users/trapias/events{/privacy}","received_events_url":"https://api.github.com/users/trapias/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/manyminds/api2go/labels/question","name":"question","color":"cc317c"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":4,"created_at":"2015-08-17T12:23:13Z","updated_at":"2015-08-17T14:59:02Z","closed_at":null,"body":"Hello,\r\nthis is not an issue, don't mean to bother anybody but would like to have some help if possible.\r\n\r\nI'm developing an API server that uses https://github.com/julienschmidt/httprouter to manage handlers, in conjunction with https://github.com/justinas/alice to easily chain handlers and https://github.com/gorilla/context to handle context variables. Since api2go also uses httprouter, I think converting my code to use it should be possible and not overkilling.  But I'm new to Go too, and hardly can see some details atm :blush: , like how to continue using my middleware handlers.\r\n\r\nI now setup my handlers like:\r\n\r\n\tcommonHandlers := alice.New(context.ClearHandler, applicationcontext.CORSHandler, applicationcontext.ConfigHandler, applicationcontext.JWTHandler, applicationcontext.LoggingHandler)\r\n\r\n\trouter.GET(\"/api/1/users\", applicationcontext.WrapHandler(commonHandlers.ThenFunc(apiserver.GetUsers)))\r\n\r\nwhere my WrapHandler() func wraps \"normal\" http handlers so that they can be used as methods but \"passing through\" the chain of handlers via next.ServeHTTP(w, r) calls:\r\n\r\n\tfunc WrapHandler(h http.Handler) httprouter.Handle {\r\n\t\treturn func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {\r\n\t\t\tcontext.Set(r, \"params\", ps)\r\n\t\t\th.ServeHTTP(w, r)\r\n\t\t}\r\n\t}\r\n\r\n\tfunc ConfigHandler(next http.Handler) http.Handler {\r\n\tfn := func(w http.ResponseWriter, r *http.Request) {\r\n\r\n\t\t\tvar cfg configuration.Configuration\r\n\t\t\tcfg = configuration.ReadConfig()\r\n\t\t\tcontext.Set(r, \"cfg\", cfg)\r\n\r\n\t\t\tnext.ServeHTTP(w, r)\r\n\t\t}\r\n\t\treturn http.HandlerFunc(fn)\r\n\t}\r\n\r\n\tfunc GetUsers(w http.ResponseWriter, r *http.Request) {\r\n\t\tcfg := context.Get(r, \"cfg\").(configuration.Configuration)\r\n\t\t// ....\r\n\t\tfmt.Fprintf(w, \"{\\\"users\\\": %v}\", string(sData))\r\n\t}\r\n\r\n\r\nSince api2go handles resources generating its own handlers, how could I convert my middleware handlers so that they can be used with api2go?\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/manyminds/api2go/issues/comments/131853770","html_url":"https://github.com/manyminds/api2go/issues/158#issuecomment-131853770","issue_url":"https://api.github.com/repos/manyminds/api2go/issues/158","id":131853770,"user":{"login":"trapias","id":2881610,"avatar_url":"https://avatars.githubusercontent.com/u/2881610?v=3","gravatar_id":"","url":"https://api.github.com/users/trapias","html_url":"https://github.com/trapias","followers_url":"https://api.github.com/users/trapias/followers","following_url":"https://api.github.com/users/trapias/following{/other_user}","gists_url":"https://api.github.com/users/trapias/gists{/gist_id}","starred_url":"https://api.github.com/users/trapias/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/trapias/subscriptions","organizations_url":"https://api.github.com/users/trapias/orgs","repos_url":"https://api.github.com/users/trapias/repos","events_url":"https://api.github.com/users/trapias/events{/privacy}","received_events_url":"https://api.github.com/users/trapias/received_events","type":"User","site_admin":false},"created_at":"2015-08-17T14:59:01Z","updated_at":"2015-08-17T14:59:01Z","body":"@wwwdata oh yes, it works perfectly!!! :grinning: \r\n\r\nAlice handlers are like my ConfigHandler above (so simple to chain indeed, I too like the simple syntax), but it works just like you tell - very happy!\r\n\r\nI now just have to understand how to extract a route from the chain of handlers. Until now I was using two different chains, one with all handlers and one without the JWT authentication handler, only used for the /login route - needed to obtain an authorization token, so it cannot of course be itself protected by authentication:\r\n\r\n\tcommonHandlers := alice.New(context.ClearHandler, applicationcontext.CORSHandler, applicationcontext.ConfigHandler, applicationcontext.JWTHandler, applicationcontext.LoggingHandler) //, applicationcontext.RecoverHandler)\r\n\tauthHandlers := alice.New(context.ClearHandler, applicationcontext.CORSHandler, applicationcontext.ConfigHandler, applicationcontext.LoggingHandler)  \r\n\r\n\t// unprotected\r\n\trouter.POST(\"/api/1/login\", applicationcontext.WrapHandler(authHandlers.ThenFunc(applicationcontext.AuthHandler)))\r\n\r\n\t// protected\r\n\trouter.GET(\"/api/1/users\", applicationcontext.WrapHandler(commonHandlers.ThenFunc(apiserver.GetUsers)))\r\n\t\r\nI now modified my code like this:\r\n\r\n\tapi := api2go.NewAPIWithMarshalers(\"api/1\", \"https://\"+cfg.Host+\":\"+cfg.Port, marshalers)\r\n\t\r\n\tuserStorage := storage.NewUserStorage()\r\n\tapi.AddResource(model.User{}, resource.UserResource{UserStorage: userStorage})\r\n\r\n\t// previous version\r\n\t// router := applicationcontext.NewRouter()\r\n\r\n\t// current version: get the router from api2go instance\r\n\trouter := api.Handler().(*httprouter.Router)\r\n\r\n\terr := http.ListenAndServeTLS(cfg.Host+\":\"+cfg.Port, \"cert.pem\", \"key.pem\", commonHandlers.Then(api.Handler()))\r\n\r\n\t// previous version, using router\r\n\t// err := http.ListenAndServeTLS(cfg.Host+\":\"+cfg.Port, \"cert.pem\", \"key.pem\", router)\r\n\r\nThe problem is now all routes go through commonHandlers, thus the authentication handler is called also for the login route. Maybe I just can check within it (the authentication handler), and bypass all checks if the route is /login. No better idea for now.\r\n\r\nThank you so much anyway, you made my day - I'll definitely go on with api2go! :grinning: Owe you :beers: !!!\r\n\r\n\r\n\r\n\r\n"}}