func getArticle(w http.ResponseWriter, r *http.Request) { // Load article. if chi.URLParam(r, "articleID") != "1" { render.Respond(w, r, data.ErrNotFound) return } article := &data.Article{ ID: 1, Title: "Article #1", Data: []string{"one", "two", "three", "four"}, CustomDataForAuthUsers: "secret data for auth'd users only", } // Simulate some context values: // 1. ?auth=true simluates authenticated session/user. // 2. ?error=true simulates random error. if r.URL.Query().Get("auth") != "" { r = r.WithContext(context.WithValue(r.Context(), "auth", true)) } if r.URL.Query().Get("error") != "" { render.Respond(w, r, errors.New("error")) return } render.Respond(w, r, article) }
// Pagination adds the values "per_page" and "page" to the context with values // from the query params. func Pagination(next http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { rawPerPage := chi.URLParam(r, "per_page") rawPage := chi.URLParam(r, "page") if len(rawPerPage) == 0 { rawPerPage = "20" } if len(rawPage) == 0 { rawPage = "0" } var err error var perPage int if perPage, err = strconv.Atoi(rawPerPage); err != nil { perPage = 20 } var page int if page, err = strconv.Atoi(rawPage); err != nil { page = 0 } ctx := r.Context() ctx = context.WithValue(ctx, 1001, perPage) ctx = context.WithValue(ctx, 1002, page) r = r.WithContext(ctx) next.ServeHTTP(w, r) } return http.HandlerFunc(fn) }
func deleteClass(w http.ResponseWriter, r *http.Request) { classType := chi.URLParam(r, "classType") className := chi.URLParam(r, "className") err := config.DeleteClass(classType, className) if err != nil { render.JSON(w, r, map[string]interface{}{"success": false, "errors": []string{err.Error()}}) return } render.JSON(w, r, map[string]interface{}{"success": true}) }
func getClassByName(w http.ResponseWriter, r *http.Request) { classType := chi.URLParam(r, "classType") className := chi.URLParam(r, "className") resp, err := config.LoadClassByName(classType, className) if err != nil { render.JSON(w, r, map[string]interface{}{"success": false, "errors": []string{err.Error()}}) return } render.JSON(w, r, map[string]interface{}{"classType": classType, "className": className, "class": resp, "success": true}) }
func getFeed(w http.ResponseWriter, r *http.Request) { feedName := chi.URLParam(r, "feedName") feedSettings, err := config.LoadWidget(feedName) if err != nil { render.JSON(w, r, map[string]interface{}{"success": false, "errors": []string{err.Error()}}) return } var items config.FeedItems feed, err := rss.Fetch(feedSettings.RssURL) if err != nil { render.JSON(w, r, map[string]interface{}{"success": false, "errors": []string{err.Error()}}) return } for _, i := range feed.Items { items.ParseItem(i) } items, err = config.SaveFeed(feedName, items, feedSettings.Count) if err != nil { render.JSON(w, r, map[string]interface{}{"success": false, "errors": []string{err.Error()}}) return } render.JSON(w, r, map[string]interface{}{"feed": items, "success": true}) }
func getWidgetByName(w http.ResponseWriter, r *http.Request) { widgetName := chi.URLParam(r, "widgetName") resp, err := config.LoadWidget(widgetName) if err != nil { render.JSON(w, r, map[string]interface{}{"success": false, "errors": []string{err.Error()}}) return } render.JSON(w, r, map[string]interface{}{"widgetName": widgetName, "widget": resp, "success": true}) }
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) } }
// Download a file func (t Controller) Download(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") if len(id) != 36 { http.Error(w, "Thumbnail not found", 404) return } thumb, err := models.FindThumbnail(t.DB, id) if err != nil { http.Error(w, "Thumbnail not found", 404) return } http.ServeFile(w, r, lib.LocalPath(thumb.Hash)) }
func putWidget(w http.ResponseWriter, r *http.Request) { widgetName := chi.URLParam(r, "widgetName") data, err := ioutil.ReadAll(r.Body) if err != nil { render.JSON(w, r, map[string]interface{}{"success": false, "errors": []string{"Error Reading Body!", err.Error()}}) return } // check for empty body? if len(data) == 0 { render.JSON(w, r, map[string]interface{}{"success": false, "errors": []string{"No widget object was passed!"}}) return } widget, err := config.SaveWidget(widgetName, data) if err != nil { render.JSON(w, r, map[string]interface{}{"success": false, "errors": []string{"Error saving Class!", err.Error()}}) return } render.JSON(w, r, map[string]interface{}{"widget": widget, "success": true}) }
func TestStripSlashesInRoute(t *testing.T) { r := chi.NewRouter() r.NotFound(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(404) w.Write([]byte("nothing here")) }) r.Get("/hi", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hi")) }) r.Route("/accounts/:accountID", func(r chi.Router) { r.Use(StripSlashes) r.Get("/query", func(w http.ResponseWriter, r *http.Request) { accountID := chi.URLParam(r, "accountID") w.Write([]byte(accountID)) }) }) ts := httptest.NewServer(r) defer ts.Close() if _, resp := testRequest(t, ts, "GET", "/hi", nil); resp != "hi" { t.Fatalf(resp) } if _, resp := testRequest(t, ts, "GET", "/hi/", nil); resp != "nothing here" { t.Fatalf(resp) } if _, resp := testRequest(t, ts, "GET", "/accounts/admin/query", nil); resp != "admin" { t.Fatalf(resp) } if _, resp := testRequest(t, ts, "GET", "/accounts/admin/query/", nil); resp != "admin" { t.Fatalf(resp) } }
// ByGet shortcut to chi.URLParam // returns the url parameter from a http.Request object. func (c *Context) ByGet(name string) string { return chi.URLParam(c.Req, name) }
func putClass(w http.ResponseWriter, r *http.Request) { classType := chi.URLParam(r, "classType") className := chi.URLParam(r, "className") data, err := ioutil.ReadAll(r.Body) if err != nil { render.JSON(w, r, map[string]interface{}{"success": false, "errors": []string{"Error Reading Body!", err.Error()}}) return } // check for empty body? if len(data) == 0 { render.JSON(w, r, map[string]interface{}{"success": false, "errors": []string{"No class object was passed!"}}) return } var class interface{} switch classType { case "vpcs": class, err = config.SaveVpcClass(className, data) case "subnets": class, err = config.SaveSubnetClass(className, data) case "instances": class, err = config.SaveInstanceClass(className, data) case "volumes": class, err = config.SaveVolumeClass(className, data) case "snapshots": class, err = config.SaveSnapshotClass(className, data) case "images": class, err = config.SaveImageClass(className, data) case "autoscalegroups": class, err = config.SaveAutoscalingGroupClass(className, data) case "launchconfigurations": class, err = config.SaveLaunchConfigurationClass(className, data) case "loadbalancers": class, err = config.SaveLoadBalancerClass(className, data) case "scalingpolicies": class, err = config.SaveScalingPolicyClass(className, data) case "alarms": class, err = config.SaveAlarmClass(className, data) case "securitygroups": class, err = config.SaveSecurityGroupClass(className, data) case "keypairs": class, err = config.SaveKeyPairClass(className, data) } if err != nil { render.JSON(w, r, map[string]interface{}{"success": false, "errors": []string{"Error saving Class!", err.Error()}}) return } render.JSON(w, r, map[string]interface{}{"classType": classType, "class": class, "success": true}) }
func getAssets(w http.ResponseWriter, r *http.Request) { // Get the listType assetType := chi.URLParam(r, "assetType") var resp interface{} var errs []error // multi-region var err error // single region switch assetType { case "addresses": resp, errs = aws.GetAddresses("", false) case "alarms": resp, errs = aws.GetAlarms() case "autoscalegroups": resp, errs = aws.GetAutoScaleGroups("") case "iamusers": resp, err = aws.GetIAMUsers("") case "images": resp, errs = aws.GetImages("", false) case "instances": resp, errs = aws.GetInstances("", false) case "keypairs": resp, errs = aws.GetKeyPairs("") case "launchconfigurations": resp, errs = aws.GetLaunchConfigurations("") case "loadbalancers": resp, errs = aws.GetLoadBalancers() case "scalingpolicies": resp, errs = aws.GetScalingPolicies() case "securitygroups": resp, errs = aws.GetSecurityGroups("") case "simpledbdomains": resp, errs = aws.GetSimpleDBDomains("") case "snapshots": resp, errs = aws.GetSnapshots("", false) case "subnets": resp, errs = aws.GetSubnets("") case "volumes": resp, errs = aws.GetVolumes("", false) case "vpcs": resp, errs = aws.GetVpcs("") /* case "buckets": // TODO resp, errs = aws.GetBuckets() */ default: err = errors.New("Unknown list type") } // Combine errors if err != nil { errs = append(errs, err) } if len(errs) == 0 { render.JSON(w, r, map[string]interface{}{"assetType": assetType, "assets": resp, "success": true}) } else { errStrs := make([]string, len(errs)) for i, e := range errs { errStrs[i] = e.Error() } render.JSON(w, r, map[string]interface{}{"assetType": assetType, "assets": resp, "success": false, "errors": errStrs}) } }
// Generate docs for the MuxBig from chi/mux_test.go func TestMuxBig(t *testing.T) { var r, sr1, sr2, sr3, sr4, sr5, sr6 *chi.Mux r = chi.NewRouter() r.Use(RequestID) // Some inline middleware, 1 // We just love Go's ast tools r.Use(func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { next.ServeHTTP(w, r) }) }) r.Group(func(r chi.Router) { r.Use(func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := context.WithValue(r.Context(), "session.user", "anonymous") next.ServeHTTP(w, r.WithContext(ctx)) }) }) r.Get("/favicon.ico", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("fav")) }) r.Get("/hubs/:hubID/view", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() s := fmt.Sprintf("/hubs/%s/view reqid:%s session:%s", chi.URLParam(r, "hubID"), ctx.Value("requestID"), ctx.Value("session.user")) w.Write([]byte(s)) }) r.Get("/hubs/:hubID/view/*", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() s := fmt.Sprintf("/hubs/%s/view/%s reqid:%s session:%s", chi.URLParamFromCtx(ctx, "hubID"), chi.URLParam(r, "*"), ctx.Value("requestID"), ctx.Value("session.user")) w.Write([]byte(s)) }) }) r.Group(func(r chi.Router) { r.Use(func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := context.WithValue(r.Context(), "session.user", "elvis") next.ServeHTTP(w, r.WithContext(ctx)) }) }) r.Get("/", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() s := fmt.Sprintf("/ reqid:%s session:%s", ctx.Value("requestID"), ctx.Value("session.user")) w.Write([]byte(s)) }) r.Get("/suggestions", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() s := fmt.Sprintf("/suggestions reqid:%s session:%s", ctx.Value("requestID"), ctx.Value("session.user")) w.Write([]byte(s)) }) r.Get("/woot/:wootID/*", func(w http.ResponseWriter, r *http.Request) { s := fmt.Sprintf("/woot/%s/%s", chi.URLParam(r, "wootID"), chi.URLParam(r, "*")) w.Write([]byte(s)) }) r.Route("/hubs", func(r chi.Router) { sr1 = r.(*chi.Mux) r.Use(func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { next.ServeHTTP(w, r) }) }) r.Route("/:hubID", func(r chi.Router) { sr2 = r.(*chi.Mux) r.Get("/", hubIndexHandler) r.Get("/touch", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() s := fmt.Sprintf("/hubs/%s/touch reqid:%s session:%s", chi.URLParam(r, "hubID"), ctx.Value("requestID"), ctx.Value("session.user")) w.Write([]byte(s)) }) sr3 = chi.NewRouter() sr3.Get("/", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() s := fmt.Sprintf("/hubs/%s/webhooks reqid:%s session:%s", chi.URLParam(r, "hubID"), ctx.Value("requestID"), ctx.Value("session.user")) w.Write([]byte(s)) }) sr3.Route("/:webhookID", func(r chi.Router) { sr4 = r.(*chi.Mux) r.Get("/", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() s := fmt.Sprintf("/hubs/%s/webhooks/%s reqid:%s session:%s", chi.URLParam(r, "hubID"), chi.URLParam(r, "webhookID"), ctx.Value("requestID"), ctx.Value("session.user")) w.Write([]byte(s)) }) }) // TODO: /webooks is not coming up as a subrouter here... // we kind of want to wrap a Router... ? // perhaps add .Router() to the middleware inline thing.. // and use that always.. or, can detect in that method.. r.Mount("/webhooks", chi.Chain(func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { next.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), "hook", true))) }) }).Handler(sr3)) // HMMMM.. only let Mount() for just a Router..? // r.Mount("/webhooks", Use(...).Router(sr3)) // ... could this work even....? // HMMMMMMMMMMMMMMMMMMMMMMMM... // even if Mount() were to record all subhandlers mounted, we still couldn't get at the // routes r.Route("/posts", func(r chi.Router) { sr5 = r.(*chi.Mux) r.Get("/", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() s := fmt.Sprintf("/hubs/%s/posts reqid:%s session:%s", chi.URLParam(r, "hubID"), ctx.Value("requestID"), ctx.Value("session.user")) w.Write([]byte(s)) }) }) }) }) r.Route("/folders/", func(r chi.Router) { sr6 = r.(*chi.Mux) r.Get("/", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() s := fmt.Sprintf("/folders/ reqid:%s session:%s", ctx.Value("requestID"), ctx.Value("session.user")) w.Write([]byte(s)) }) r.Get("/public", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() s := fmt.Sprintf("/folders/public reqid:%s session:%s", ctx.Value("requestID"), ctx.Value("session.user")) w.Write([]byte(s)) }) r.Get("/in", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}).ServeHTTP) r.With(func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { next.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), "search", true))) }) }).Get("/search", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("searching..")) }) }) }) fmt.Println(docgen.JSONRoutesDoc(r)) // docgen.PrintRoutes(r) }
func hubIndexHandler(w http.ResponseWriter, r *http.Request) { ctx := r.Context() s := fmt.Sprintf("/hubs/%s reqid:%s session:%s", chi.URLParam(r, "hubID"), ctx.Value("requestID"), ctx.Value("session.user")) w.Write([]byte(s)) }