diff --git a/CHANGELOG.md b/CHANGELOG.md index 754cd2f2..2afb4e05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## v2.1.0 (2017-03-30) + +- Minor improvements and update to the chi core library +- Introduced a brand new `chi/render` sub-package to complete the story of building +APIs to offer a pattern for managing well-defined request / response payloads. Please +check out the updated `_examples/rest` example for how it works. +- Added `MethodNotAllowed(h http.HandlerFunc)` to chi.Router interface + + ## v2.0.0 (2017-01-06) - After many months of v2 being in an RC state with many companies and users running it in diff --git a/README.md b/README.md index 19cb9b6a..eba288d7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -chi -=== +# chi + [![GoDoc Widget]][GoDoc] [![Travis Widget]][Travis] @@ -232,7 +232,9 @@ type Routes interface { ``` Each routing method accepts a URL `pattern` and chain of `handlers`. The URL pattern -supports named params (ie. `/users/:userID`) and wildcards (ie. `/admin/*`). +supports named params (ie. `/users/:userID`) and wildcards (ie. `/admin/*`). URL parameters +can be fetched at runtime by calling `chi.URLParam(r, "userID")` for named parameters +and `chi.URLParam(r, "*")` for a wildcard parameter. ### Middleware handlers diff --git a/_examples/rest/main.go b/_examples/rest/main.go index 3259d4bc..fd0ca20a 100644 --- a/_examples/rest/main.go +++ b/_examples/rest/main.go @@ -56,16 +56,6 @@ import ( var routes = flag.Bool("routes", false, "Generate router documentation") -// TODO: make a new example as _examples/metrics -// func TrackRoute(next http.Handler) http.Handler { -// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// next.ServeHTTP(w, r) -// rctx := chi.RouteContext(r.Context()) -// routePattern := strings.Join(rctx.RoutePatterns, "") -// fmt.Println("route:", routePattern) -// }) -// } - func main() { flag.Parse() @@ -75,7 +65,6 @@ func main() { r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Use(render.SetContentType(render.ContentTypeJSON)) - // r.Use(TrackMetric) r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("root.")) diff --git a/render/README.md b/render/README.md index ba611ca3..59f3d6db 100644 --- a/render/README.md +++ b/render/README.md @@ -1,3 +1,20 @@ -## chi/render is experimental package +# chi/render -Please, note that the render pkg API might change. +The `render` sub-package helps manage HTTP request / response payloads. + +Every a well-designed, robust and maintainable Web Service / REST API also needs +well-*defined* request and response payloads. + +Typically in a REST API application, you will have your data models (objects/structs) +that hold lower-level runtime application state, and at times you need to assemble, +decorate, hide or transform the representation before responding to a client, and +also the client will likely provide the same structure as input from its requests. + +This is where `render` comes in - offering a few simple helpers and interfaces to +provide a simple pattern for managing payload encoding and decoding. + +We've also combined it with some helpers for responding to content types and parsing +request bodies. Please have a look at the [rest](https://github.com/pressly/chi/blob/master/_examples/rest/main.go) +example which uses the latest chi/render sub-pkg. + +All feedback is welcome, thank you! diff --git a/render/content_type.go b/render/content_type.go index 4e9b6623..69ba9e48 100644 --- a/render/content_type.go +++ b/render/content_type.go @@ -10,7 +10,7 @@ var ( ContentTypeCtxKey = &contextKey{"ContentType"} ) -// A ContentType is an enumeration of common HTTP content types. +// ContentType is an enumeration of common HTTP content types. type ContentType int // ContentTypes handled by this package. diff --git a/render/render.go b/render/render.go index 045b06b2..98c8c7b1 100644 --- a/render/render.go +++ b/render/render.go @@ -5,14 +5,18 @@ import ( "reflect" ) +// Renderer interface for managing response payloads. type Renderer interface { Render(w http.ResponseWriter, r *http.Request) error } +// Binder interface for managing request payloads. type Binder interface { Bind(r *http.Request) error } +// Bind decodes a request body and executes the Binder method of the +// payload structure. func Bind(r *http.Request, v Binder) error { if err := Decode(r, v); err != nil { return err @@ -20,6 +24,7 @@ func Bind(r *http.Request, v Binder) error { return binder(r, v) } +// Render renders a single payload and respond to the client request. func Render(w http.ResponseWriter, r *http.Request, v Renderer) error { if err := renderer(w, r, v); err != nil { return err @@ -28,6 +33,7 @@ func Render(w http.ResponseWriter, r *http.Request, v Renderer) error { return nil } +// RenderList renders a slice of payloads and responds to the client request. func RenderList(w http.ResponseWriter, r *http.Request, l []Renderer) error { for _, v := range l { if err := renderer(w, r, v); err != nil {