1 package middleware 2 3 import ( 4 "context" 5 "net/http" 6 "strings" 7 8 "github.com/go-chi/chi" 9 ) 10 11 var ( 12 // URLFormatCtxKey is the context.Context key to store the URL format data 13 // for a request. 14 URLFormatCtxKey = &contextKey{"URLFormat"} 15 ) 16 17 // URLFormat is a middleware that parses the url extension from a request path and stores it 18 // on the context as a string under the key `middleware.URLFormatCtxKey`. The middleware will 19 // trim the suffix from the routing path and continue routing. 20 // 21 // Routers should not include a url parameter for the suffix when using this middleware. 22 // 23 // Sample usage.. for url paths: `/articles/1`, `/articles/1.json` and `/articles/1.xml` 24 // 25 // func routes() http.Handler { 26 // r := chi.NewRouter() 27 // r.Use(middleware.URLFormat) 28 // 29 // r.Get("/articles/{id}", ListArticles) 30 // 31 // return r 32 // } 33 // 34 // func ListArticles(w http.ResponseWriter, r *http.Request) { 35 // urlFormat, _ := r.Context().Value(middleware.URLFormatCtxKey).(string) 36 // 37 // switch urlFormat { 38 // case "json": 39 // render.JSON(w, r, articles) 40 // case "xml:" 41 // render.XML(w, r, articles) 42 // default: 43 // render.JSON(w, r, articles) 44 // } 45 // } 46 // 47 func URLFormat(next http.Handler) http.Handler { 48 fn := func(w http.ResponseWriter, r *http.Request) { 49 ctx := r.Context() 50 51 var format string 52 path := r.URL.Path 53 54 if strings.Index(path, ".") > 0 { 55 base := strings.LastIndex(path, "/") 56 idx := strings.Index(path[base:], ".") 57 58 if idx > 0 { 59 idx += base 60 format = path[idx+1:] 61 62 rctx := chi.RouteContext(r.Context()) 63 rctx.RoutePath = path[:idx] 64 } 65 } 66 67 r = r.WithContext(context.WithValue(ctx, URLFormatCtxKey, format)) 68 69 next.ServeHTTP(w, r) 70 } 71 return http.HandlerFunc(fn) 72 } 73