From 1220ca38f2aa0ebcad6baf05ec337a8388104b69 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Tue, 30 Jun 2015 11:51:08 -0700 Subject: [PATCH] Add recipes section in docs Signed-off-by: Vishal Rana --- context.go | 16 ++-- recipes/file-upload/public/index.html | 16 ++++ recipes/file-upload/server.go | 51 ++++++++++++ .../graceful-shutdown}/grace/server.go | 4 +- .../graceful-shutdown}/graceful/server.go | 4 +- recipes/streaming-file-upload/server.go | 77 +++++++++++++++++ .../streaming-response}/server.go | 0 {examples => recipes}/websocket/server.go | 0 website/docs/guide.md | 2 +- website/docs/recipes/file-upload.md | 82 +++++++++++++++++++ website/docs/recipes/graceful-shutdown.md | 52 ++++++++++++ website/docs/recipes/streaming-response.md | 53 ++++++++++++ website/docs/recipes/websocket.md | 26 ++++++ website/echo/base.html | 4 +- website/mkdocs.yml | 13 +-- 15 files changed, 380 insertions(+), 20 deletions(-) create mode 100644 recipes/file-upload/public/index.html create mode 100644 recipes/file-upload/server.go rename {examples => recipes/graceful-shutdown}/grace/server.go (68%) rename {examples => recipes/graceful-shutdown}/graceful/server.go (69%) create mode 100644 recipes/streaming-file-upload/server.go rename {examples/stream => recipes/streaming-response}/server.go (100%) rename {examples => recipes}/websocket/server.go (100%) create mode 100644 website/docs/recipes/file-upload.md create mode 100644 website/docs/recipes/graceful-shutdown.md create mode 100644 website/docs/recipes/streaming-response.md create mode 100644 website/docs/recipes/websocket.md diff --git a/context.go b/context.go index bc9a64f0..6a994909 100644 --- a/context.go +++ b/context.go @@ -4,6 +4,8 @@ import ( "encoding/json" "net/http" + "fmt" + "golang.org/x/net/websocket" ) @@ -103,19 +105,21 @@ func (c *Context) JSON(code int, i interface{}) error { return json.NewEncoder(c.response).Encode(i) } -// String sends a text/plain response with status code. -func (c *Context) String(code int, s string) error { +// String formats according to a format specifier and sends text/plain response +// with status code. +func (c *Context) String(code int, format string, a ...interface{}) error { c.response.Header().Set(ContentType, TextPlain) c.response.WriteHeader(code) - _, err := c.response.Write([]byte(s)) + _, err := fmt.Fprintf(c.response, format, a...) return err } -// HTML sends a text/html response with status code. -func (c *Context) HTML(code int, html string) error { +// HTML formats according to a format specifier and sends text/html response with +// status code. +func (c *Context) HTML(code int, format string, a ...interface{}) error { c.response.Header().Set(ContentType, TextHTML) c.response.WriteHeader(code) - _, err := c.response.Write([]byte(html)) + _, err := fmt.Fprintf(c.response, format, a...) return err } diff --git a/recipes/file-upload/public/index.html b/recipes/file-upload/public/index.html new file mode 100644 index 00000000..eb56c800 --- /dev/null +++ b/recipes/file-upload/public/index.html @@ -0,0 +1,16 @@ + + + + + Multipart File Upload + + +

Upload Files

+
+ Name:
+ Email:
+ Files:

+ +
+ + diff --git a/recipes/file-upload/server.go b/recipes/file-upload/server.go new file mode 100644 index 00000000..7438931e --- /dev/null +++ b/recipes/file-upload/server.go @@ -0,0 +1,51 @@ +package main + +import ( + "io" + "os" + + "net/http" + + "github.com/labstack/echo" +) + +func upload(c *echo.Context) error { + req := c.Request() + + // req.ParseMultipartForm(16 << 20) // Max memory 16 MiB + + // Read form fields + name := req.FormValue("name") + email := req.FormValue("email") + + // Read files + files := req.MultipartForm.File["files"] + for _, f := range(files) { + // Source file + src, err := f.Open() + if err != nil { + return err + } + defer src.Close() + + // Destination file + dst, err := os.Create(f.Filename) + if err != nil { + return err + } + defer dst.Close() + + if _, err = io.Copy(dst, src); err != nil { + return err + } + } + return c.String(http.StatusOK, "Thank You! %s <%s>, %d files uploaded successfully.", + name, email, len(files)) +} + +func main() { + e := echo.New() + e.Index("public/index.html") + e.Post("/upload", upload) + e.Run(":1323") +} diff --git a/examples/grace/server.go b/recipes/graceful-shutdown/grace/server.go similarity index 68% rename from examples/grace/server.go rename to recipes/graceful-shutdown/grace/server.go index fee4ffae..9dbeb7d4 100644 --- a/examples/grace/server.go +++ b/recipes/graceful-shutdown/grace/server.go @@ -11,10 +11,8 @@ func main() { // Setup e := echo.New() e.Get("/", func(c *echo.Context) error { - c.String(http.StatusOK, "Six sick bricks tick") - return nil + return c.String(http.StatusOK, "Six sick bricks tick") }) - // Use github.com/facebookgo/grace/gracehttp gracehttp.Serve(e.Server(":1323")) } diff --git a/examples/graceful/server.go b/recipes/graceful-shutdown/graceful/server.go similarity index 69% rename from examples/graceful/server.go rename to recipes/graceful-shutdown/graceful/server.go index 2c862c92..3a872691 100644 --- a/examples/graceful/server.go +++ b/recipes/graceful-shutdown/graceful/server.go @@ -12,10 +12,8 @@ func main() { // Setup e := echo.New() e.Get("/", func(c *echo.Context) error { - c.String(http.StatusOK, "Sue sews rose on slow jor crows nose") - return nil + return c.String(http.StatusOK, "Sue sews rose on slow jor crows nose") }) - // Use github.com/tylerb/graceful graceful.ListenAndServe(e.Server(":1323"), 5*time.Second) } diff --git a/recipes/streaming-file-upload/server.go b/recipes/streaming-file-upload/server.go new file mode 100644 index 00000000..5e12ffad --- /dev/null +++ b/recipes/streaming-file-upload/server.go @@ -0,0 +1,77 @@ +package main + +import ( + "io/ioutil" + + "github.com/labstack/echo" + "io" + "os" + "net/http" +) + +func upload(c *echo.Context) error { + mr, err := c.Request().MultipartReader() + if err != nil { + return err + } + + // Read form field `name` + part, err := mr.NextPart() + if err != nil { + return err + } + defer part.Close() + b, err := ioutil.ReadAll(part) + if err != nil { + return err + } + name := string(b) + + // Read form field `email` + part, err = mr.NextPart() + if err != nil { + return err + } + defer part.Close() + b, err = ioutil.ReadAll(part) + if err != nil { + return err + } + email := string(b) + + println(name, email) + + // Read files + i := 0 + for { + part, err := mr.NextPart() + if err != nil { + if err == io.EOF { + break + } + return err + } + defer part.Close() + + file, err := os.Create(part.FileName()) + if err != nil { + return err + } + defer file.Close() + + if _, err := io.Copy(file, part); err != nil { + return err + } + i++ + } + return c.String(http.StatusOK, "Thank You! %s <%s>, %d files uploaded successfully.", + name, email, i) +} + +func main() { + e := echo.New() + e.SetDebug(true) + e.Index("../file-upload/public/index.html") + e.Post("/upload", upload) + e.Run(":1323") +} diff --git a/examples/stream/server.go b/recipes/streaming-response/server.go similarity index 100% rename from examples/stream/server.go rename to recipes/streaming-response/server.go diff --git a/examples/websocket/server.go b/recipes/websocket/server.go similarity index 100% rename from examples/websocket/server.go rename to recipes/websocket/server.go diff --git a/website/docs/guide.md b/website/docs/guide.md index a20bd7a9..d75a3adc 100644 --- a/website/docs/guide.md +++ b/website/docs/guide.md @@ -49,7 +49,7 @@ Enables debug mode. ## Routing Echo's router is [fast, optimized](https://github.com/labstack/echo#benchmark) and -flexible. It's based on [redix tree](http://en.wikipedia.org/wiki/Radix_tree) +flexible. It's based on [radix tree](http://en.wikipedia.org/wiki/Radix_tree) data structure which makes routing lookup really fast. It leverages [sync pool](https://golang.org/pkg/sync/#Pool) to reuse memory and achieve zero dynamic memory allocation with no GC overhead. diff --git a/website/docs/recipes/file-upload.md b/website/docs/recipes/file-upload.md new file mode 100644 index 00000000..39b146e3 --- /dev/null +++ b/website/docs/recipes/file-upload.md @@ -0,0 +1,82 @@ +## Multipart File Upload + +`server.go` + +```go +package main + +import ( + "io" + "os" + + "net/http" + + "github.com/labstack/echo" +) + +func upload(c *echo.Context) error { + req := c.Request() + + // req.ParseMultipartForm(16 << 20) // Max memory 16 MiB + + // Read form fields + name := req.FormValue("name") + email := req.FormValue("email") + + // Read files + files := req.MultipartForm.File["files"] + for _, f := range(files) { + // Source file + src, err := f.Open() + if err != nil { + return err + } + defer src.Close() + + // Destination file + dst, err := os.Create(f.Filename) + if err != nil { + return err + } + defer dst.Close() + + if _, err = io.Copy(dst, src); err != nil { + return err + } + } + return c.String(http.StatusOK, "Thank You! %s <%s>, %d files uploaded successfully.", + name, email, len(files)) +} + +func main() { + e := echo.New() + e.Index("public/index.html") + e.Post("/upload", upload) + e.Run(":1323") +} + +``` + +`index.html` + +```html + + + + + Multipart File Upload + + +

Upload Files

+
+ Name:
+ Email:
+ Files:

+ +
+ + + +``` + +## [Source Code] diff --git a/website/docs/recipes/graceful-shutdown.md b/website/docs/recipes/graceful-shutdown.md new file mode 100644 index 00000000..9ac5cac2 --- /dev/null +++ b/website/docs/recipes/graceful-shutdown.md @@ -0,0 +1,52 @@ +## Graceful Shutdown + +### With [graceful](https://github.com/tylerb/graceful) + +`server.go` + +```go +package main + +import ( + "net/http" + "time" + + "github.com/labstack/echo" + "github.com/tylerb/graceful" +) + +func main() { + // Setup + e := echo.New() + e.Get("/", func(c *echo.Context) error { + return c.String(http.StatusOK, "Sue sews rose on slow jor crows nose") + }) + + graceful.ListenAndServe(e.Server(":1323"), 5*time.Second) +} +``` + +### With [grace](https://github.com/facebookgo/grace) + +`server.go` + +```go +package main + +import ( + "net/http" + + "github.com/facebookgo/grace/gracehttp" + "github.com/labstack/echo" +) + +func main() { + // Setup + e := echo.New() + e.Get("/", func(c *echo.Context) error { + return c.String(http.StatusOK, "Six sick bricks tick") + }) + + gracehttp.Serve(e.Server(":1323")) +} +``` diff --git a/website/docs/recipes/streaming-response.md b/website/docs/recipes/streaming-response.md new file mode 100644 index 00000000..fbc714ab --- /dev/null +++ b/website/docs/recipes/streaming-response.md @@ -0,0 +1,53 @@ +## Streaming Response + +`server.go` + +```go +package main + +import ( + "net/http" + "time" + + "encoding/json" + + "github.com/labstack/echo" +) + +type ( + Geolocation struct { + Altitude float64 + Latitude float64 + Longitude float64 + } +) + +var ( + locations = []Geolocation{ + {-97, 37.819929, -122.478255}, + {1899, 39.096849, -120.032351}, + {2619, 37.865101, -119.538329}, + {42, 33.812092, -117.918974}, + {15, 37.77493, -122.419416}, + } +) + +func main() { + e := echo.New() + e.Get("/stream", func(c *echo.Context) error { + c.Response().Header().Set(echo.ContentType, echo.ApplicationJSON) + c.Response().WriteHeader(http.StatusOK) + for _, l := range locations { + if err := json.NewEncoder(c.Response()).Encode(l); err != nil { + return err + } + c.Response().Flush() + time.Sleep(1 * time.Second) + } + return nil + }) + e.Run(":1323") +} +``` + +## [Source Code]() diff --git a/website/docs/recipes/websocket.md b/website/docs/recipes/websocket.md new file mode 100644 index 00000000..b826fed4 --- /dev/null +++ b/website/docs/recipes/websocket.md @@ -0,0 +1,26 @@ +## WebSocket + +`server.go` + +```go +package main + +import ( + "io" + + "github.com/labstack/echo" + mw "github.com/labstack/echo/middleware" +) + +func main() { + e := echo.New() + e.Use(mw.Logger()) + e.WebSocket("/ws", func(c *echo.Context) error { + io.Copy(c.Socket(), c.Socket()) + return nil + }) + e.Run(":1323") +} +``` + +## [Source Code]() diff --git a/website/echo/base.html b/website/echo/base.html index 4f0260c1..f005d8f6 100644 --- a/website/echo/base.html +++ b/website/echo/base.html @@ -14,7 +14,7 @@ - + {%- for path in extra_css %} @@ -75,4 +75,4 @@ {%- endfor %} - \ No newline at end of file + diff --git a/website/mkdocs.yml b/website/mkdocs.yml index 13d59c70..05dee5d4 100644 --- a/website/mkdocs.yml +++ b/website/mkdocs.yml @@ -1,11 +1,14 @@ site_name: Echo - theme: journal - theme_dir: echo - copyright: '© 2015 LabStack' - repo_url: https://github.com/labstack/echo - google_analytics: ['UA-51208124-3', 'auto'] +pages: + - Home: index.md + - Guide: guide.md + - Recipes: + - File Upload: recipes/file-upload.md + - Graceful Shutdown: recipes/graceful-shutdown.md + - Streaming Response: recipes/streaming-response.md + - WebSocket: recipes/websocket.md