func TestThrottleClientTimeout(t *testing.T) { r := chi.NewRouter() r.Use(ThrottleBacklog(10, 50, time.Second*10)) r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) time.Sleep(time.Second * 5) // Expensive operation. w.Write(testContent) }) server := httptest.NewServer(r) client := http.Client{ Timeout: time.Second * 3, // Maximum waiting time. } var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func(i int) { defer wg.Done() _, err := client.Get(server.URL) assert.Error(t, err) }(i) } wg.Wait() server.Close() }
func main() { // Setup the logger logger := logrus.New() logger.Formatter = &logrus.JSONFormatter{} // optional / configurable, see docs // Routes r := chi.NewRouter() r.Use(middleware.RequestID) r.Use(NewStructuredLogger(logger)) r.Use(middleware.Recoverer) r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("welcome")) }) r.Get("/wait", func(w http.ResponseWriter, r *http.Request) { time.Sleep(1 * time.Second) LogEntrySetField(r, "wait", true) w.Write([]byte("hi")) }) r.Get("/panic", func(w http.ResponseWriter, r *http.Request) { panic("oops") }) http.ListenAndServe(":3333", r) }
func main() { r := chi.NewRouter() r.Use(middleware.RequestID) r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Use(render.UsePresenter(v3.Presenter)) // API version 3 (latest) by default. // Redirect for Example convenience. r.Get("/", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/v3/articles/1", 302) }) // API version 3. r.Route("/v3", func(r chi.Router) { r.Mount("/articles", articleRouter()) }) // API version 2. r.Route("/v2", func(r chi.Router) { r.Use(render.UsePresenter(v2.Presenter)) r.Mount("/articles", articleRouter()) }) // API version 1. r.Route("/v1", func(r chi.Router) { r.Use(randomErrorMiddleware) // Simulate random error, ie. version 1 is buggy. r.Use(render.UsePresenter(v1.Presenter)) r.Mount("/articles", articleRouter()) }) http.ListenAndServe(":3333", r) }
func TestSimple(t *testing.T) { r := chi.NewRouter() r.Use(TokenAuth.Verifier, jwtauth.Authenticator) r.Get("/", func(ctx context.Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte("welcome")) }) ts := httptest.NewServer(r) defer ts.Close() // sending unauthorized requests if status, resp := testRequest(t, ts, "GET", "/", nil, nil); status != 401 && resp != "Unauthorized\n" { t.Fatalf(resp) } h := http.Header{} h.Set("Authorization", "BEARER "+newJwtToken([]byte("wrong"), map[string]interface{}{})) if status, resp := testRequest(t, ts, "GET", "/", h, nil); status != 401 && resp != "Unauthorized\n" { t.Fatalf(resp) } h.Set("Authorization", "BEARER asdf") if status, resp := testRequest(t, ts, "GET", "/", h, nil); status != 401 && resp != "Unauthorized\n" { t.Fatalf(resp) } // sending authorized requests if status, resp := testRequest(t, ts, "GET", "/", newAuthHeader(), nil); status != 200 && resp != "welcome" { t.Fatalf(resp) } }
func accountsRouter() chi.Router { r := chi.NewRouter() r.Use(sup1) r.Get("/", listAccounts) r.Post("/", createAccount) r.Get("/hi", hiAccounts) r.Group(func(r chi.Router) { r.Use(sup2) r.Get("/hi2", func(ctx context.Context, w http.ResponseWriter, r *http.Request) { v := ctx.Value("sup2").(string) w.Write([]byte(fmt.Sprintf("hi2 - '%s'", v))) }) }) r.Route("/:accountID", func(r chi.Router) { r.Use(accountCtx) r.Get("/", getAccount) r.Put("/", updateAccount) r.Get("/*", other) }) return r }
func router() http.Handler { r := chi.NewRouter() // Protected routes r.Group(func(r chi.Router) { // Seek, verify and validate JWT tokens r.Use(TokenAuth.Verifier) // Handle valid / invalid tokens. In this example, we use // the provided authenticator middleware, but you can write your // own very easily, look at the Authenticator method in jwtauth.go // and tweak it, its not scary. r.Use(jwtauth.Authenticator) r.Get("/admin", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() token := ctx.Value("jwt").(*jwt.Token) claims := token.Claims w.Write([]byte(fmt.Sprintf("protected area. hi %v", claims["user_id"]))) }) }) // Public routes r.Group(func(r chi.Router) { r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("welcome anonymous")) }) }) return r }
// New returns a new blank Engine instance with no middleware attached func New(opts Options) *Engine { namespace := opts.Namespace if len(namespace) == 0 { namespace = "/" } engine := &Engine{} engine.Router = &Router{ namespace: namespace, engine: engine, mux: chi.NewRouter(), } engine.options = opts engine.pool.New = func() interface{} { ctx := &Context{ Engine: engine, render: render.New(render.Options{ Layout: "layout", }), } return ctx } return engine }
func TestThrottleMaximum(t *testing.T) { r := chi.NewRouter() r.Use(ThrottleBacklog(50, 50, time.Second*5)) r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) time.Sleep(time.Second * 2) // Expensive operation. w.Write(testContent) }) server := httptest.NewServer(r) client := http.Client{ Timeout: time.Second * 60, // Maximum waiting time. } var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func(i int) { defer wg.Done() res, err := client.Get(server.URL) assert.NoError(t, err) assert.Equal(t, http.StatusOK, res.StatusCode) buf, err := ioutil.ReadAll(res.Body) assert.NoError(t, err) assert.Equal(t, testContent, buf) }(i) } // Wait less time than what the server takes to reply. time.Sleep(time.Second * 1) // At this point the server is still processing, all the following request // will be beyond the server capacity. for i := 0; i < 100; i++ { wg.Add(1) go func(i int) { defer wg.Done() res, err := client.Get(server.URL) assert.NoError(t, err) buf, err := ioutil.ReadAll(res.Body) assert.Equal(t, http.StatusServiceUnavailable, res.StatusCode) assert.Equal(t, errCapacityExceeded, strings.TrimSpace(string(buf))) }(i) } wg.Wait() server.Close() }
//New create all routers under one Handler func New() http.Handler { r := chi.NewRouter() r.Mount("/auth", auth.Routes()) r.Mount("/apps", apps.Routes()) return r }
//Routes returns chi's Router for Auth APIs func Routes() chi.Router { r := chi.NewRouter() r.Post("/register", m.BodyParser(registerRequestBuilder, 512), register) r.Post("/login", m.BodyParser(loginRequestBuilder, 512), login) r.Head("/logout", logout) return r }
func main() { r := chi.NewRouter() r.Use(middleware.RequestID) r.Use(middleware.Logger) r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hello world")) }) http.ListenAndServe(":3333", r) }
func articleRouter() http.Handler { r := chi.NewRouter() r.Get("/", listArticles) r.Route("/:articleID", func(r chi.Router) { r.Get("/", getArticle) // r.Put("/", updateArticle) // r.Delete("/", deleteArticle) }) return r }
func TestThrottleTriggerGatewayTimeout(t *testing.T) { r := chi.NewRouter() r.Use(ThrottleBacklog(50, 100, time.Second*5)) r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) time.Sleep(time.Second * 10) // Expensive operation. w.Write(testContent) }) server := httptest.NewServer(r) client := http.Client{ Timeout: time.Second * 60, // Maximum waiting time. } var wg sync.WaitGroup // These requests will be processed normally until they finish. for i := 0; i < 50; i++ { wg.Add(1) go func(i int) { defer wg.Done() res, err := client.Get(server.URL) assert.NoError(t, err) assert.Equal(t, http.StatusOK, res.StatusCode) }(i) } time.Sleep(time.Second * 1) // These requests will wait for the first batch to complete but it will take // too much time, so they will eventually receive a timeout error. for i := 0; i < 50; i++ { wg.Add(1) go func(i int) { defer wg.Done() res, err := client.Get(server.URL) assert.NoError(t, err) buf, err := ioutil.ReadAll(res.Body) assert.Equal(t, http.StatusServiceUnavailable, res.StatusCode) assert.Equal(t, errTimedOut, strings.TrimSpace(string(buf))) }(i) } wg.Wait() server.Close() }
func main() { r := chi.NewRouter() // Limit to 5 requests globally. r.Use(throttler.Limit(5)) r.Get("/*", handler) admin := chi.NewRouter() // Limit to 2 requests for admin route admin.Use(throttler.Limit(2)) admin.Get("/", handler) r.Mount("/admin/", admin) fmt.Printf("Try running the following commands (in different terminal):\n\n") fmt.Printf("for i in `seq 1 10`; do (curl 127.0.0.1:8000/ &); done\n\n") fmt.Printf("for i in `seq 1 10`; do (curl 127.0.0.1:8000/admin/ &); done\n\n") http.ListenAndServe(":8000", r) }
func initChi() { h := chi.NewRouter() h.Get("/", func(ctx context.Context, w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain; charset=utf-8") fmt.Fprintf(w, "Hello, World") }) h.Get("/:name", func(ctx context.Context, w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain; charset=utf-8") fmt.Fprintf(w, "Hello, %s", chi.URLParams(ctx)["name"]) }) registerHandler("chi", h) }
func Profiler() http.Handler { r := chi.NewRouter() r.Handle("/vars", expVars) r.Handle("/pprof/", pprof.Index) r.Handle("/pprof/cmdline", pprof.Cmdline) r.Handle("/pprof/profile", pprof.Profile) r.Handle("/pprof/symbol", pprof.Symbol) r.Handle("/pprof/block", pprof.Handler("block").ServeHTTP) r.Handle("/pprof/heap", pprof.Handler("heap").ServeHTTP) r.Handle("/pprof/goroutine", pprof.Handler("goroutine").ServeHTTP) r.Handle("/pprof/threadcreate", pprof.Handler("threadcreate").ServeHTTP) return r }
func main() { r := chi.NewRouter() r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hi")) }) workDir, _ := os.Getwd() filesDir := filepath.Join(workDir, "files") r.FileServer("/files", http.Dir(filesDir)) http.ListenAndServe(":3333", r) }
func main() { r := chi.NewRouter() // use middleware r.Use(middleware.Logger) // add routing r.Get("/", apiIndex) r.Route("/todo", func(r chi.Router) { r.Get("/", getTodoList) }) http.ListenAndServe(":3333", r) }
// A completely separate router for administrator routes func adminRouter() http.Handler { // or chi.Router { r := chi.NewRouter() r.Use(AdminOnly) r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("admin: index")) }) r.Get("/accounts", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("admin: list accounts..")) }) r.Get("/users/:userId", func(ctx context.Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte(fmt.Sprintf("admin: view user id %v", chi.URLParams(ctx)["userId"]))) }) return r }
func main() { r := chi.NewRouter() r.Use(middleware.Logger) r.Use(httpcoala.Route("HEAD", "GET")) // or, Route("*") r.Get("/", func(w http.ResponseWriter, r *http.Request) { time.Sleep(100 * time.Millisecond) // expensive op w.WriteHeader(200) w.Write([]byte("hi")) }) http.ListenAndServe(":1111", r) }
// NewRouter creates new chakra Mux and appends its route to acl.route, unless // the passed route is chakra.UseParentRoute. func NewRouter(route string) *Mux { if route == "" { panic("new router created without acl route") } if accessControl == nil { panic("you have not defined access control function with SetAC") } r := &Mux{chi.NewRouter()} if route != UseParentRoute { r.Mux.Use(Route(route)) } return r }
func TestRedirectSlashes(t *testing.T) { r := chi.NewRouter() // This middleware must be mounted at the top level of the router, not at the end-handler // because then it'll be too late and will end up in a 404 r.Use(RedirectSlashes) r.NotFound(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(404) w.Write([]byte("nothing here")) }) r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("root")) }) r.Route("/accounts/:accountID", func(r chi.Router) { r.Get("/", func(w http.ResponseWriter, r *http.Request) { accountID := chi.URLParam(r, "accountID") w.Write([]byte(accountID)) }) }) ts := httptest.NewServer(r) defer ts.Close() if status, resp := testRequest(t, ts, "GET", "/", nil); resp != "root" && status != 200 { t.Fatalf(resp) } // NOTE: the testRequest client will follow the redirection.. if status, resp := testRequest(t, ts, "GET", "//", nil); resp != "root" && status != 200 { t.Fatalf(resp) } if status, resp := testRequest(t, ts, "GET", "/accounts/admin", nil); resp != "admin" && status != 200 { t.Fatalf(resp) } // NOTE: the testRequest client will follow the redirection.. if status, resp := testRequest(t, ts, "GET", "/accounts/admin/", nil); resp != "admin" && status != 200 { t.Fatalf(resp) } if status, resp := testRequest(t, ts, "GET", "/nothing-here", nil); resp != "nothing here" && status != 200 { t.Fatalf(resp) } }
// StartAPI Starts the API listener on port 8081 func StartAPI() { r := chi.NewRouter() cors := cors.New(cors.Options{ AllowedOrigins: []string{"*"}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"}, AllowCredentials: true, }) r.Use(cors.Handler) r.Use(middleware.Recoverer) //r.Use(middleware.Logger) r.Route("/api", func(r chi.Router) { r.Route("/dashboard", func(r chi.Router) { r.Route("/widgets", func(r chi.Router) { r.Get("/", getWidgets) r.Get("/events", getEvents) r.Get("/feed/:feedName", getFeed) r.Get("/options", getWidgetOptions) r.Get("/names", getWidgetNames) r.Get("/name/:widgetName", getWidgetByName) r.Put("/name/:widgetName", putWidget) r.Delete("/name/:widgetName", deleteWidget) }) }) r.Route("/assets", func(r chi.Router) { r.Route("/:assetType", func(r chi.Router) { r.Get("/", getAssets) }) }) r.Route("/classes", func(r chi.Router) { r.Get("/export", exportClasses) //r.Get("/import", importClasses) // TODO r.Route("/:classType", func(r chi.Router) { r.Get("/", getClasses) r.Get("/options", getClassOptions) r.Get("/names", getClassNames) r.Get("/name/:className", getClassByName) r.Put("/name/:className", putClass) r.Delete("/name/:className", deleteClass) }) }) }) http.ListenAndServe(":8081", r) }
func main() { r := chi.NewRouter() r.Use(middleware.RequestID) r.Use(middleware.RealIP) r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(".")) }) r.Mount("/users", usersResource{}.Routes()) r.Mount("/todos", todosResource{}.Routes()) http.ListenAndServe(":3333", r) }
// Routes creates a REST router for the todos resource func (rs usersResource) Routes() chi.Router { r := chi.NewRouter() // r.Use() // some middleware.. r.Get("/", rs.List) // GET /todos - read a list of todos r.Post("/", rs.Create) // POST /todos - create a new todo and persist it r.Put("/", rs.Delete) r.Route("/:id", func(r chi.Router) { // r.Use(rs.TodoCtx) // lets have a todos map, and lets actually load/manipulate r.Get("/", rs.Get) // GET /todos/:id - read a single todo by :id r.Put("/", rs.Update) // PUT /todos/:id - update a single todo by :id r.Delete("/", rs.Delete) // DELETE /todos/:id - delete a single todo by :id }) return r }
func Router() chi.Router { r := chi.NewRouter() r.Use(middleware.RequestID) r.Use(middleware.RealIP) r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Use(func(h chi.Handler) chi.Handler { return chi.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { ctx = context.WithValue(ctx, "example", true) h.ServeHTTPC(ctx, w, r) }) }) r.Get("/", apiIndex) return r }
func main() { r := chi.NewRouter() r.Use(middleware.RequestID) r.Use(middleware.RealIP) r.Use(middleware.Logger) r.Use(func(h chi.Handler) chi.Handler { return chi.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { ctx = context.WithValue(ctx, "example", true) h.ServeHTTPC(ctx, w, r) }) }) r.Get("/", apiIndex) r.Mount("/accounts", accountsRouter()) http.ListenAndServe(":3333", r) }
func TestThrottleBacklog(t *testing.T) { r := chi.NewRouter() r.Use(ThrottleBacklog(10, 50, time.Second*10)) r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) time.Sleep(time.Second * 1) // Expensive operation. w.Write(testContent) }) server := httptest.NewServer(r) client := http.Client{ Timeout: time.Second * 5, // Maximum waiting time. } var wg sync.WaitGroup // The throttler proccesses 10 consecutive requests, each one of those // requests lasts 1s. The maximum number of requests this can possible serve // before the clients time out (5s) is 40. for i := 0; i < 40; i++ { wg.Add(1) go func(i int) { defer wg.Done() res, err := client.Get(server.URL) assert.NoError(t, err) assert.Equal(t, http.StatusOK, res.StatusCode) buf, err := ioutil.ReadAll(res.Body) assert.NoError(t, err) assert.Equal(t, testContent, buf) }(i) } wg.Wait() server.Close() }
func Routes(qmd *qmd.Qmd) http.Handler { handlers.Qmd = qmd r := chi.NewRouter() r.Use(middleware.RequestID) r.Use(middleware.RealIP) r.Use(middleware.NoCache) r.Use(middleware.Recoverer) r.Use(middleware.Logger) r.Use(qmd.ClosingResponder) r.Get("/", handlers.Index) r.Get("/ping", handlers.Ping) r.Post("/scripts/:filename", handlers.CreateJob) r.Get("/jobs", handlers.Jobs) r.Get("/jobs/*", GetLongID, handlers.Job) return r }
// Profiler is a convenient subrouter used for mounting net/http/pprof. ie. // // func MyService() http.Handler { // r := chi.NewRouter() // // ..middlewares // r.Mount("/debug", profiler.Router()) // // ..routes // return r // } func Profiler() http.Handler { r := chi.NewRouter() r.Use(NoCache) r.Get("/", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, r.RequestURI+"/pprof/", 301) }) r.HandleFunc("/pprof", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, r.RequestURI+"/", 301) }) r.HandleFunc("/pprof/", pprof.Index) r.HandleFunc("/pprof/cmdline", pprof.Cmdline) r.HandleFunc("/pprof/profile", pprof.Profile) r.HandleFunc("/pprof/symbol", pprof.Symbol) r.Handle("/pprof/block", pprof.Handler("block")) r.Handle("/pprof/heap", pprof.Handler("heap")) r.Handle("/pprof/goroutine", pprof.Handler("goroutine")) r.Handle("/pprof/threadcreate", pprof.Handler("threadcreate")) r.HandleFunc("/vars", expVars) return r }