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:
parent
2f70d3e1c7
commit
c5a3575d4c
@ -21,7 +21,7 @@
|
||||
|
||||
## Performance
|
||||
|
||||
![Performance](http://i.imgur.com/F2V7TfO.png)
|
||||
![Performance](https://i.imgur.com/F2V7TfO.png)
|
||||
|
||||
## Quick Start
|
||||
|
||||
|
40
context.go
40
context.go
@ -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 {
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
build:
|
||||
rm -rf public && hugo
|
||||
rm -rf public/v3 && hugo
|
||||
|
@ -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",
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
``` -->
|
||||
|
@ -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).
|
||||
|
@ -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.
|
50
website/content/guide/migration.md
Normal file
50
website/content/guide/migration.md
Normal 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)
|
@ -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
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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),
|
||||
|
@ -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 }}
|
||||
|
3
website/static/scripts/main.js
Normal file
3
website/static/scripts/main.js
Normal file
@ -0,0 +1,3 @@
|
||||
function version(e) {
|
||||
window.location = e.value;
|
||||
}
|
Loading…
Reference in New Issue
Block a user