1
0
mirror of https://github.com/labstack/echo.git synced 2025-01-12 01:22:21 +02:00

updated migration guide

Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
Vishal Rana 2016-11-13 09:36:57 -08:00
parent 2f70d3e1c7
commit c5a3575d4c
17 changed files with 147 additions and 237 deletions

View File

@ -21,7 +21,7 @@
## Performance
![Performance](http://i.imgur.com/F2V7TfO.png)
![Performance](https://i.imgur.com/F2V7TfO.png)
## Quick Start

View File

@ -13,8 +13,6 @@ import (
"os"
"path/filepath"
"strings"
"golang.org/x/net/websocket"
)
type (
@ -175,16 +173,15 @@ type (
}
context struct {
request *http.Request
response *Response
webSocket *websocket.Conn
path string
pnames []string
pvalues []string
query url.Values
handler HandlerFunc
store Map
echo *Echo
request *http.Request
response *Response
path string
pnames []string
pvalues []string
query url.Values
handler HandlerFunc
store Map
echo *Echo
}
)
@ -238,15 +235,22 @@ func (c *context) SetPath(p string) {
c.path = p
}
func (c *context) Param(name string) (value string) {
l := len(c.pnames)
func (c *context) Param(name string) string {
for i, n := range c.pnames {
if n == name && i < l {
value = c.pvalues[i]
break
if i < len(c.pnames) {
if strings.HasPrefix(n, name) {
return c.pvalues[i]
}
// Param name with aliases
for _, p := range strings.Split(n, ",") {
if p == name {
return c.pvalues[i]
}
}
}
}
return
return ""
}
func (c *context) ParamNames() []string {

View File

@ -250,6 +250,18 @@ func TestContextPathParam(t *testing.T) {
assert.Equal(t, "501", c.Param("fid"))
}
func TestContextPathParamNamesAlais(t *testing.T) {
e := New()
req, _ := http.NewRequest(GET, "/", nil)
c := e.NewContext(req, nil)
c.SetParamNames("id,name")
c.SetParamValues("joe")
assert.Equal(t, "joe", c.Param("id"))
assert.Equal(t, "joe", c.Param("name"))
}
func TestContextFormValue(t *testing.T) {
f := make(url.Values)
f.Set("name", "Jon Snow")

View File

@ -1,5 +1,7 @@
package echo
import "strings"
type (
// Router is the registry of all registered routes for an `Echo` instance for
// request matching and URL path parameter parsing.
@ -170,7 +172,12 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
if h != nil {
cn.addHandler(method, h)
cn.ppath = ppath
cn.pnames = pnames
for i, n := range cn.pnames {
// Param name aliases
if !strings.Contains(n, pnames[i]) {
cn.pnames[i] += "," + pnames[i]
}
}
}
}
return

View File

@ -3,6 +3,7 @@ package echo
import (
"fmt"
"net/http"
"strings"
"testing"
"github.com/stretchr/testify/assert"
@ -823,9 +824,11 @@ func TestRouterAPI(t *testing.T) {
c := e.NewContext(nil, nil).(*context)
for _, route := range gitHubAPI {
r.Find(route.Method, route.Path, c)
for i, n := range c.pnames {
if assert.NotEmpty(t, n) {
assert.Equal(t, n, c.pnames[i])
for _, n := range c.pnames {
for _, p := range strings.Split(n, ",") {
if assert.NotEmpty(t, p) {
assert.Equal(t, c.Param(p), ":"+p)
}
}
}
}

View File

@ -1,2 +1,2 @@
build:
rm -rf public && hugo
rm -rf public/v3 && hugo

View File

@ -1,9 +1,10 @@
{
"baseurl": "https://echo.labstack.com",
"baseurl": "https://echo.labstack.com/",
"languageCode": "en-us",
"title": "Echo - Fast and unfancy HTTP server framework for Go (Golang)",
"canonifyurls": true,
"googleAnalytics": "UA-85059636-2",
"publishdir": "public/v3",
"permalinks": {
"guide": "/guide/:filename",
"middleware": "/middleware/:filename",

View File

@ -11,8 +11,6 @@ description = "Customizing Echo"
### HTTP Error Handler
`Echo#SetHTTPErrorHandler(h HTTPErrorHandler)` registers a custom `Echo#HTTPErrorHandler`.
Default HTTP error handler rules:
- If error is of type `Echo#HTTPError` it sends HTTP response with status code `HTTPError.Code`
@ -20,79 +18,32 @@ and message `HTTPError.Message`.
- Else it sends `500 - Internal Server Error`.
- If debug mode is enabled, it uses `error.Error()` as status message.
### Debug
You can also set a custom HTTP error handler using `Echo#HTTPErrorHandler`.
`Echo#SetDebug(on bool)` enable/disable debug mode.
### Debugging
`Echo#Debug` enables/disables debug mode.
### Logging
#### Custom Logger
`Echo#SetLogger(l log.Logger)`
SetLogger defines a custom logger.
#### Log Output
`Echo#SetLogOutput(w io.Writer)` sets the output destination for the logger. Default
value `os.Stdout`
`Echo#Logger.SetOutput(io.Writer)` sets the output destination for the logger.
Default value `os.Stdout`
To completely disable logs use `Echo#SetLogOutput(io.Discard)`
To completely disable logs use `Echo#Logger.SetOutput(io.Discard)` or `Echo#Logger.SetLevel(log.OFF)`
#### Log Level
`Echo#SetLogLevel(l log.Level)`
`Echo#Logger.SetLevel(log.Lvl)`
SetLogLevel sets the log level for the logger. Default value `5` (OFF).
SetLogLevel sets the log level for the logger. Default value `OFF`.
Possible values:
- `0` (DEBUG)
- `1` (INFO)
- `2` (WARN)
- `3` (ERROR)
- `4` (FATAL)
- `5` (OFF)
- `DEBUG`
- `INFO`
- `WARN`
- `ERROR`
- `OFF`
### HTTP Engine
Echo currently supports standard and [fasthttp](https://github.com/valyala/fasthttp)
server engines. Echo utilizes interfaces to abstract the internal implementation
of these servers so you can seamlessly switch from one engine to another based on
your preference.
#### Running a standard HTTP server
`e.Run(standard.New(":1323"))`
#### Running a fasthttp server
`e.Run(fasthttp.New(":1323"))`
#### Running a server with TLS configuration
`e.Run(<engine>.WithTLS(":1323", "<certFile>", "<keyFile>"))`
#### Running a server with engine configuration
`e.Run(<engine>.WithConfig(<config>))`
##### Configuration
```go
Config struct {
Address string // TCP address to listen on.
Listener net.Listener // Custom `net.Listener`. If set, server accepts connections on it.
TLSCertFile string // TLS certificate file path.
TLSKeyFile string // TLS key file path.
ReadTimeout time.Duration // Maximum duration before timing out read of the request.
WriteTimeout time.Duration // Maximum duration before timing out write of the response.
}
```
#### Access internal server instance and configure its properties
```go
s := standard.New(":1323")
s.MaxHeaderBytes = 1 << 20
e.Run(s)
```
You can also set a custom logger using `Echo#Logger`.

View File

@ -9,82 +9,47 @@ description = "Frequently asked questions in Echo"
## FAQ
Q: **How to retrieve `*http.Request` and `http.ResponseWriter` from `echo.Context`?**
Q: How to retrieve `*http.Request` and `http.ResponseWriter` from `echo.Context`?
- `http.Request` > `c.Request().(*standard.Request).Request`
- `http.Request` > `c.Request()`
- `http.ResponseWriter` > `c.Response()`
> Standard engine only
Q: **How to use standard handler `func(http.ResponseWriter, *http.Request)` with Echo?**
Q: How to use standard handler `func(http.ResponseWriter, *http.Request)` with Echo?
```go
func handler(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Handler!")
io.WriteString(w, "Echo!")
}
func main() {
e := echo.New()
e.GET("/", standard.WrapHandler(http.HandlerFunc(handler)))
e.Run(standard.New(":1323"))
e.GET("/", echo.WrapHandler(http.HandlerFunc(handler)))
e.Start(":1323")
}
```
Q: **How to use fasthttp handler `func(fasthttp.RequestCtx)` with Echo?**
```go
func handler(c *fh.RequestCtx) {
io.WriteString(c, "Handler!")
}
func main() {
e := echo.New()
e.GET("/", fasthttp.WrapHandler(handler))
e.Run(fasthttp.New(":1323"))
}
```
Q: **How to use standard middleware `func(http.Handler) http.Handler` with Echo?**
Q: How to use standard middleware `func(http.Handler) http.Handler` with Echo?
```go
func middleware(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
println("Middleware!")
println("middleware")
h.ServeHTTP(w, r)
})
}
func main() {
e := echo.New()
e.Use(standard.WrapMiddleware(middleware))
e.Use(echo.WrapMiddleware(middleware))
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "OK")
return c.String(http.StatusOK, "Echo!")
})
e.Run(standard.New(":1323"))
e.Start(":1323")
}
```
Q: **How to use fasthttp middleware `func(http.Handler) http.Handler` with Echo?**
Q: How to run Echo on a specific IP address?
```go
func middleware(h fh.RequestHandler) fh.RequestHandler {
return func(ctx *fh.RequestCtx) {
println("Middleware!")
h(ctx)
}
}
func main() {
e := echo.New()
e.Use(fasthttp.WrapMiddleware(middleware))
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "OK")
})
e.Run(fasthttp.New(":1323"))
}
e.Start("<ip>:<port>")
```
<!-- ### Q: How to run Echo on specific IP and port?
```go
``` -->

View File

@ -15,9 +15,9 @@ Echo is developed and tested using Go `1.6.x` and `1.7.x`
$ go get -u github.com/labstack/echo
```
> Ideally, you should rely on a [package manager](https://github.com/avelino/awesome-go#package-management) like glide or govendor to use a specific [version](https://github.com/labstack/echo/releases) of Echo.
> Ideally you should rely on a [package manager](https://github.com/avelino/awesome-go#package-management) like glide or govendor to use a specific [version](https://github.com/labstack/echo/releases) of Echo.
### [Migrating from v1](/guide/migrating)
### [Migrating Guide](/guide/migration)
Echo follows [semantic versioning](http://semver.org) managed through GitHub releases.
Specific version of Echo can be installed using a [package manager](https://github.com/avelino/awesome-go#package-management).

View File

@ -1,93 +0,0 @@
+++
title = "Migrating"
description = "Migrating from Echo v1 to v2"
[menu.side]
name = "Migrating"
parent = "guide"
weight = 2
+++
## Migrating from v1
### Change Log
- Good news, 85% of the API remains the same.
- `Engine` interface to abstract `HTTP` server implementation, allowing
us to use HTTP servers beyond Go standard library. It currently supports standard and [fasthttp](https://github.com/valyala/fasthttp) server.
- Context, Request and Response are converted to interfaces. [More...](https://github.com/labstack/echo/issues/146)
- Handler signature is changed to `func (c echo.Context) error`.
- Dropped auto wrapping of handler and middleware to enforce compile time check.
- APIs to run middleware before or after the router, which doesn't require `Echo#Hook` API now.
- Ability to define middleware at route level.
- `Echo#HTTPError` exposed it's fields `Code` and `Message`.
- Option to specify log format in logger middleware and default logger.
#### API
v1 | v2
--- | ---
`Context#Query()` | `Context#QueryParam()`
`Context#Form()` | `Context#FormValue()`
### FAQ
Q. How to access original objects from interfaces?
A. Only if you need to...
```go
// `*http.Request`
c.Request().(*standard.Request).Request
// `*http.URL`
c.Request().URL().(*standard.URL).URL
// Request `http.Header`
c.Request().Header().(*standard.Header).Header
// `http.ResponseWriter`
c.Response().(*standard.Response).ResponseWriter
// Response `http.Header`
c.Response().Header().(*standard.Header).Header
```
Q. How to use standard handler and middleware?
A.
```go
package main
import (
"net/http"
"github.com/labstack/echo"
"github.com/labstack/echo/engine/standard"
)
// Standard middleware
func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
println("standard middleware")
next.ServeHTTP(w, r)
})
}
// Standard handler
func handler(w http.ResponseWriter, r *http.Request) {
println("standard handler")
}
func main() {
e := echo.New()
e.Use(standard.WrapMiddleware(middleware))
e.GET("/", standard.WrapHandler(http.HandlerFunc(handler)))
e.Run(standard.New(":1323"))
}
```
### Next?
- Browse through [recipes](/recipes/hello-world) freshly converted to v2.
- Read documentation and dig into test cases.

View File

@ -0,0 +1,50 @@
+++
title = "Migration"
description = "Migration"
[menu.side]
name = "Migration"
parent = "guide"
weight = 2
+++
## V3
### Change Log
- Automatic TLS certificates via [Let's Encrypt](https://letsencrypt.org/)
- Built-in support for graceful shutdown
- Dropped static middleware in favor of `Echo#Static`
- Utility functions to wrap standard handler and middleware
- `Map` type as shorthand for `map[string]interface{}`
- Context now wraps standard net/http Request and Response
- New configuration
- `Echo#ShutdownTimeout`
- `Echo#DisableHTTP2`
- New API
- `Echo#Start()`
- `Echo#StartTLS()`
- `Echo#StartAutoTLS()`
- `Echo#StartServer()`
- `Echo#Shutdown()`
- `Echo#ShutdownTLS()`
- `Context#Scheme()`
- `Context#RealIP()`
- `Context#IsTLS()`
- Exposed the following properties instead of setter / getter functions on `Echo` instance:
- `Binder`
- `Renderer`
- `HTTPErrorHandler`
- `Debug`
- `Logger`
- Enhanced redirect and CORS middleware
- Dropped API
- `Echo#Run()`
- `Context#P()`
- Dropped standard `Context` support
- Dropped support for `fasthttp`
- Dropped deprecated API
- Moved `Logger` interface to root level
- Moved website and recipes to the main repo
- Updated docs and fixed numerous issues
### [Recipes](/recipes/hello-world)

View File

@ -8,7 +8,6 @@ title = "Index"
- Optimized HTTP router which smartly prioritize routes
- Build robust and scalable RESTful APIs
- Run with standard HTTP server or FastHTTP server
- Group APIs
- Extensible middleware framework
- Define middleware at root, group or route level
@ -18,11 +17,12 @@ title = "Index"
- Template rendering with any template engine
- Define your format for the logger
- Highly customizable
- Automatic TLS via Let’s Encrypt
- Built-in graceful shutdown
## Performance
<img style="width: 75%;" src="http://i.imgur.com/F2V7TfO.png" alt="Performance">
<img style="width: 75%;" src="https://i.imgur.com/F2V7TfO.png" alt="Performance">
## Quick Start

View File

@ -40,3 +40,4 @@
<script async defer id="github-bjs" src="//buttons.github.io/buttons.js"></script>
<script src="https://cdn.labstack.com/scripts/prism.js"></script>
<script src="https://cdn.labstack.com/scripts/doc.js"></script>
<script src="{{ .Site.BaseURL }}scripts/main.js"></script>

View File

@ -24,7 +24,7 @@
<link rel="stylesheet" href="https://cdn.labstack.com/styles/prism.css">
<link rel="stylesheet" href="https://cdn.labstack.com/styles/base.css">
<link rel="stylesheet" href="https://cdn.labstack.com/styles/doc.css">
<link rel="stylesheet" href="{{ .Site.BaseURL }}/styles/main.css">
<link rel="stylesheet" href="{{ .Site.BaseURL}}/styles/main.css">
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),

View File

@ -5,9 +5,15 @@
<a class="support w3-btn w3-white w3-border w3-border-theme w3-round-xlarge" href="/support-echo">
<i class="fa fa-heart" aria-hidden="true"></i> Support Echo
</a>
<h4>
<select class="w3-select w3-border" onchange="version(this);">
<option value="/v2">v2</option>
<option value="/" selected>v3</option>
</select>
</h4>
{{ $currentNode := . }}
{{ range .Site.Menus.side }}
<h4>{{ .Pre }} {{ .Name }}</h4>
<h3>{{ .Pre }} {{ .Name }}</h3>
{{ range .Children }}
<a{{ if $currentNode.IsMenuCurrent "side" . }} class="active"{{ end }} href="{{ .URL }}">
{{ .Name }}

View File

@ -0,0 +1,3 @@
function version(e) {
window.location = e.value;
}