From 81f09b34fd6a339f1653f395572945d795fdbc0e Mon Sep 17 00:00:00 2001 From: Antonio Pagano Date: Tue, 25 Oct 2016 08:53:20 -0500 Subject: [PATCH 1/7] [doc] adding graceful documentation and example. --- recipe/graceful-shutdown/server.go | 22 ++++++++++++++++++++ website/content/recipes/graceful-shutdown.md | 10 ++++----- 2 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 recipe/graceful-shutdown/server.go diff --git a/recipe/graceful-shutdown/server.go b/recipe/graceful-shutdown/server.go new file mode 100644 index 000000000..db0ab70f2 --- /dev/null +++ b/recipe/graceful-shutdown/server.go @@ -0,0 +1,22 @@ +package main + +import ( + "time" + + "github.com/labstack/echo" +) + +func main() { + e := echo.New() + + //Setting up the termination timeout to 30 seconds. + e.ShutdownTimeout = 30 * time.Second + + e.GET("/", func(ctx echo.Context) error { + return ctx.String(200, "OK") + }) + + if err := e.Start(":1323"); err != nil { + e.Logger.Fatal(err) + } +} diff --git a/website/content/recipes/graceful-shutdown.md b/website/content/recipes/graceful-shutdown.md index 3e14a1f24..f32e8c9e8 100644 --- a/website/content/recipes/graceful-shutdown.md +++ b/website/content/recipes/graceful-shutdown.md @@ -9,17 +9,15 @@ description = "Graceful shutdown recipe / example for Echo" ## Graceful Shutdown Recipe -### Using [grace](https://github.com/facebookgo/grace) +Echo now ships with graceful server termination inside it, to accomplish it Echo uses `github.com/tylerb/graceful` library. -`server.go` - -{{< embed "graceful-shutdown/grace/server.go" >}} +By Default echo uses 15 seconds as shutdown timeout, giving 15 secs to open connections at the time the server starts to shut-down. -### Using [graceful](https://github.com/tylerb/graceful) +In order to change this default 15 seconds you could change the `ShutdownTimeout` property of your Echo instance as needed by doing something like: `server.go` -{{< embed "graceful-shutdown/graceful/server.go" >}} +{{< embed "graceful-shutdown/server.go" >}} ### Maintainers From a1d8ef791b9c605713dda4f2c03be10d3bc5e8a3 Mon Sep 17 00:00:00 2001 From: Antonio Pagano Date: Tue, 25 Oct 2016 10:04:54 -0500 Subject: [PATCH 2/7] adding myself to the maintainers list and minor comment formatting change --- recipe/graceful-shutdown/server.go | 2 +- website/content/recipes/graceful-shutdown.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/recipe/graceful-shutdown/server.go b/recipe/graceful-shutdown/server.go index db0ab70f2..ee9edaf07 100644 --- a/recipe/graceful-shutdown/server.go +++ b/recipe/graceful-shutdown/server.go @@ -9,7 +9,7 @@ import ( func main() { e := echo.New() - //Setting up the termination timeout to 30 seconds. + // Setting up the termination timeout to 30 seconds. e.ShutdownTimeout = 30 * time.Second e.GET("/", func(ctx echo.Context) error { diff --git a/website/content/recipes/graceful-shutdown.md b/website/content/recipes/graceful-shutdown.md index f32e8c9e8..08288dd70 100644 --- a/website/content/recipes/graceful-shutdown.md +++ b/website/content/recipes/graceful-shutdown.md @@ -22,8 +22,8 @@ In order to change this default 15 seconds you could change the `ShutdownTimeout ### Maintainers - [mertenvg](https://github.com/mertenvg) +- [apaganobeleno](https://github.com/apaganobeleno) ### Source Code - [graceful]({{< source "graceful-shutdown/graceful" >}}) -- [grace]({{< source "graceful-shutdown/grace" >}}) From d5761e88c61ecd1d2ff90fbc448ab1063e23a81b Mon Sep 17 00:00:00 2001 From: Antonio Pagano Date: Tue, 25 Oct 2016 10:50:27 -0500 Subject: [PATCH 3/7] [doc] updating code on the guides/context.md and guides/cookies.md to use v3 code. --- website/content/guide/context.md | 2 +- website/content/guide/cookies.md | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/website/content/guide/context.md b/website/content/guide/context.md index eb2607aad..cce48289b 100644 --- a/website/content/guide/context.md +++ b/website/content/guide/context.md @@ -49,7 +49,7 @@ e.Use(func(h echo.HandlerFunc) echo.HandlerFunc { **Use in handler** ```go -e.Get("/", func(c echo.Context) error { +e.GET("/", func(c echo.Context) error { cc := c.(*CustomContext) cc.Foo() cc.Bar() diff --git a/website/content/guide/cookies.md b/website/content/guide/cookies.md index f7d4894c4..51e5a9452 100644 --- a/website/content/guide/cookies.md +++ b/website/content/guide/cookies.md @@ -31,21 +31,23 @@ Attribute | Optional `Secure` | Yes `HTTPOnly` | Yes +Echo uses go standard `http.Cookie` object to add/retrieve cookies from the context received in the handler function. + ### Create a Cookie ```go func writeCookie(c echo.Context) error { - cookie := new(echo.Cookie) - cookie.SetName("username") - cookie.SetValue("jon") - cookie.SetExpires(time.Now().Add(24 * time.Hour)) + cookie := new(http.Cookie) + cookie.Name = "username" + cookie.Value = "jon" + cookie.Expires = time.Now().Add(24 * time.Hour) c.SetCookie(cookie) return c.String(http.StatusOK, "write a cookie") } ``` -- Cookie is created using `new(echo.Cookie)`. -- Attributes for the cookie are set using `Setter` functions. +- Cookie is created using `new(http.Cookie)`. +- Attributes for the cookie are set assigning to the `http.Cookie` instance public attributes. - Finally `c.SetCookie(cookies)` adds a `Set-Cookie` header in HTTP response. ### Read a Cookie @@ -56,8 +58,8 @@ func readCookie(c echo.Context) error { if err != nil { return err } - fmt.Println(cookie.Name()) - fmt.Println(cookie.Value()) + fmt.Println(cookie.Name) + fmt.Println(cookie.Value) return c.String(http.StatusOK, "read a cookie") } ``` @@ -70,8 +72,8 @@ func readCookie(c echo.Context) error { ```go func readAllCookies(c echo.Context) error { for _, cookie := range c.Cookies() { - fmt.Println(cookie.Name()) - fmt.Println(cookie.Value()) + fmt.Println(cookie.Name) + fmt.Println(cookie.Value) } return c.String(http.StatusOK, "read all cookie") } From df378e892d65afb73f7fd48b9d58943205b69095 Mon Sep 17 00:00:00 2001 From: Antonio Pagano Date: Tue, 25 Oct 2016 15:35:47 -0500 Subject: [PATCH 4/7] [doc] updating error-handling and request to v3 codebase --- website/content/guide/error-handling.md | 13 +++++++++---- website/content/guide/request.md | 16 +++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/website/content/guide/error-handling.md b/website/content/guide/error-handling.md index 7aa5448f7..c78d4c06e 100644 --- a/website/content/guide/error-handling.md +++ b/website/content/guide/error-handling.md @@ -29,15 +29,20 @@ import ( func main() { e := echo.New() - e.Use(func(c echo.Context) error { + e.Use(func(handler echo.HandlerFunc) echo.HandlerFunc { // Extract the credentials from HTTP request header and perform a security // check - + // For invalid credentials - return echo.NewHTTPError(http.StatusUnauthorized) + return func(c echo.Context) error { + return echo.NewHTTPError(http.StatusUnauthorized) + } }) + e.GET("/welcome", welcome) - e.Run(":1323") + if err := e.Start(":1323"); err != nil { + e.Logger.Fatal(err.Error()) + } } func welcome(c echo.Context) error { diff --git a/website/content/guide/request.md b/website/content/guide/request.md index f4ec131eb..cfe8141fc 100644 --- a/website/content/guide/request.md +++ b/website/content/guide/request.md @@ -57,9 +57,7 @@ $ curl -d "name=joe" http://localhost:1323/users ### Path Parameter -Registered path parameter can be retrieved either by name `Context#Param(name string) string` -or by index `Context#P(i int) string`. Getting parameter by index gives a slightly -better performance. +Registered path parameter can be retrieved by name `Context#Param(name string) string`. *Example* @@ -68,9 +66,6 @@ e.GET("/users/:name", func(c echo.Context) error { // By name name := c.Param("name") - // By index - name := c.P(0) - return c.String(http.StatusOK, name) }) ``` @@ -88,10 +83,13 @@ middleware for logging purpose. *Example* ```go -e.Use(func(c echo.Context) error { - println(c.Path()) // Prints `/users/:name` - return nil +e.Use(func(handler echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + println(c.Path()) + return handler(c) + } }) + e.GET("/users/:name", func(c echo.Context) error) { return c.String(http.StatusOK, name) }) From bd2a116e3ba3749b955da94da1fb711a5164c53e Mon Sep 17 00:00:00 2001 From: Antonio Pagano Date: Tue, 25 Oct 2016 16:47:16 -0500 Subject: [PATCH 5/7] [doc] updating templates documentation --- website/content/guide/templates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/content/guide/templates.md b/website/content/guide/templates.md index 4c0c7d3a0..9118a2b61 100644 --- a/website/content/guide/templates.md +++ b/website/content/guide/templates.md @@ -47,7 +47,7 @@ Example below shows how to use Go `html/template`: ```go e := echo.New() - e.SetRenderer(t) + e.Renderer = t e.GET("/hello", Hello) ``` From 1eef1cf62e8b33da869787a7659c3d568b5c1fa0 Mon Sep 17 00:00:00 2001 From: Antonio Pagano Date: Sat, 29 Oct 2016 20:34:56 -0500 Subject: [PATCH 6/7] [doc] cleaning hello-world documentation for v3 --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3d5e00c9f..d53c3ee6b 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,8 @@ package main import ( "net/http" + "github.com/labstack/echo" - "github.com/labstack/echo/engine/standard" ) func main() { @@ -54,7 +54,10 @@ func main() { e.GET("/", func(c echo.Context) error { return c.String(http.StatusOK, "Hello, World!") }) - e.Run(standard.New(":1323")) + + if err := e.Start(":1323"); err != nil { + e.Logger.Fatal(err.Error()) + } } ``` From 07fa1c95a15e3d550081451bff6de39e53b10e7e Mon Sep 17 00:00:00 2001 From: Antonio Pagano Date: Tue, 1 Nov 2016 08:28:52 -0500 Subject: [PATCH 7/7] [content] adding website index content based on #667 --- website/content/index.md | 82 +++++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/website/content/index.md b/website/content/index.md index 3c9115376..4f7760356 100644 --- a/website/content/index.md +++ b/website/content/index.md @@ -57,7 +57,10 @@ func main() { e.GET("/", func(c echo.Context) error { return c.String(http.StatusOK, "Hello, World!") }) - e.Run(standard.New(":1323")) + + if err := e.Start(":1323"); err != nil { + e.Logger.Fatal(err.Error()) + } } ``` @@ -85,8 +88,10 @@ e.DELETE("/users/:id", deleteUser) func getUser(c echo.Context) error { // User ID from path `users/:id` id := c.Param("id") + return c.String(http.StatusOK, id) } ``` +Browse to http://localhost:1323/users/Joe and you should see 'Joe' on the page. ### Query Parameters @@ -97,9 +102,13 @@ func show(c echo.Context) error { // Get team and member from the query string team := c.QueryParam("team") member := c.QueryParam("member") + + return c.String(http.StatusOK, "team:" + team + ", member:" + member) } ``` +Browse to http://localhost:1323/show?team=x-men&member=wolverine and you should see 'team:x-men, member:wolverine' on the page. + ### Form `application/x-www-form-urlencoded` `POST` `/save` @@ -114,9 +123,17 @@ func save(c echo.Context) error { // Get name and email name := c.FormValue("name") email := c.FormValue("email") + + return c.String(http.StatusOK, "name:" + name + ", email:" + email) } ``` +Run the following command. +```sh +$ curl -F "name=Joe Smith" -F "email=joe@labstack.com" http://localhost:1323/save +// => name:Joe Smith, email:joe@labstack.com +``` + ### Form `multipart/form-data` `POST` `/save` @@ -124,41 +141,52 @@ func save(c echo.Context) error { name | value :--- | :--- name | Joe Smith -email | joe@labstack.com avatar | avatar ```go func save(c echo.Context) error { - // Get name and email + // Get name name := c.FormValue("name") - email := c.FormValue("email") // Get avatar avatar, err := c.FormFile("avatar") - if err != nil { - return err - } - - // Source - src, err := avatar.Open() - if err != nil { - return err - } - defer src.Close() - - // Destination - dst, err := os.Create(avatar.Filename) - if err != nil { - return err - } - defer dst.Close() + if err != nil { + return err + } + + // Source + src, err := avatar.Open() + if err != nil { + return err + } + defer src.Close() + + // Destination + dst, err := os.Create(avatar.Filename) + if err != nil { + return err + } + defer dst.Close() + + // Copy + if _, err = io.Copy(dst, src); err != nil { + return err + } + + return c.HTML(http.StatusOK, "Thank you! " + name + "") +} +``` - // Copy - if _, err = io.Copy(dst, src); err != nil { - return err - } +Run the following command. +```sh +$ curl -F "name=Joe Smith" -F "avatar=@/path/to/your/avatar.png" http://localhost:1323/save +// => Thank you! Joe Smith +``` - return c.HTML(http.StatusOK, "Thank you!") -} +To check the uploaded image, run the following command. +```sh +cd +ls avatar.png +// => avatar.png ``` ### Handling Request