Echo

June 17, 2026 · View on GitHub

Go Go Report Card 中文文档

Echo is a fast and unfancy web framework for Go (Golang). Up to 10x faster than the rest.

This package need >= go 1.25

Features

  • 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.
  • Handy functions to send variety of HTTP responses.
  • Centralized HTTP error handling.
  • Template rendering with multiple engine support (standard, Jet, SSE, etc).
  • Define your format for the logger.
  • Highly customizable.
  • Business error code system.
  • Form data filtering and binding.
  • Transaction support.
  • Reverse proxy with load balancing (random, round-robin).
  • URL rewriting with reverse/unrewrite support.
  • Rate limiting (with memory and Redis backends).
  • Request queue for concurrency control.
  • IP filtering.
  • Distributed tracing (OpenTracing).
  • Server-Sent Events (SSE).

Quick Start

Installation

$ go get github.com/webx-top/echo

Hello, World!

Create server.go

package main

import (
	"net/http"
	"github.com/webx-top/echo"
	"github.com/webx-top/echo/engine/standard"
)

func main() {
	e := echo.New()
	e.Get("/", func(c echo.Context) error {
		return c.String("Hello, World!", http.StatusOK)
	})
	e.Run(standard.New(":1323"))
}

Start server

$ go run server.go

Browse to http://localhost:1323 and you should see Hello, World! on the page.

Routing

e.Post("/users", saveUser)
e.Get("/users/:id", getUser)
e.Put("/users/:id", updateUser)
e.Delete("/users/:id", deleteUser)
e.Get("/user/<id:[\\d]+>", getUser)

Support two parameter syntaxes: :param and <param:regexp>.

Path Parameters

func getUser(c echo.Context) error {
	// User ID from path `users/:id`
	id := c.Param("id")
	// or id := c.Paramx("id").Uint64()
}

Query Parameters

/show?team=x-men&member=wolverine

func show(c echo.Context) error {
	// Get team and member from the query string
	team := c.Query("team")
	member := c.Query("member")
	age := c.Queryx("age").Uint()
}

Form application/x-www-form-urlencoded

POST /save

namevalue
nameJoe Smith
emailjoe@labstack.com
func save(c echo.Context) error {
	// Get name and email
	name := c.Form("name")
	email := c.Form("email")
	age := c.Formx("age").Uint()
}

Form multipart/form-data

POST /save

namevalue
nameJoe Smith
emailjoe@labstack.com
avataravatar
func save(c echo.Context) error {
	// Get name and email
	name := c.Form("name")
	email := c.Form("email")

	//------------
	// Get avatar
	//------------
	_, err := c.SaveUploadedFile("avatar","./")
	return err
}

Handling Request

  • Bind JSON or XML payload into Go struct based on Content-Type request header.
  • Render response as JSON or XML with status code.
type User struct {
	Name  string `json:"name" xml:"name"`
	Email string `json:"email" xml:"email"`
}

e.Post("/users", func(c echo.Context) error {
	u := new(User)
	if err := c.MustBind(u); err != nil {
		return err
	}
	return c.JSON(u, http.StatusCreated)
	// or
	// return c.XML(u, http.StatusCreated)
})

Form Data Filter (FormFilter)

Filter and transform form data before binding.

import "github.com/webx-top/echo/formfilter"

ff := formfilter.New()
ff.Add(
    formfilter.StringToSlice("ids", ","),
    formfilter.DateRange("created", "2006-01-02"),
)

// Pass filter to Bind/MustBind directly
u := new(User)
c.MustBind(u, ff.Build())

Static Content

Serve any file from static directory for path /static/*.

e.Use(mw.Static(&mw.StaticOptions{
	Root:"static", // static file root directory
	Path:"/static/", // URL path for static files
	Browse:true, // show file list
}))

Embedded File Handler

Serve embedded files with index.html support via embed.FileSystems.

import "github.com/webx-top/echo/handler/embed"

//go:embed www/*
var wwwFS embed.FS

fs := embed.NewFileSystems()
fs.Register(wwwFS)
e.Get("/*", embed.File(fs))

Embedded Static Content (Bindata)

Serve go-bindata generated embedded static files as middleware.

import (
	"github.com/admpub/go-bindata-assetfs"
	"github.com/webx-top/echo/middleware/bindata"
)

//go:generate go-bindata -o=bindata_assetfs.go -pkg=main static/...
//go:generate go-bindata-assetfs -o=bindata_assetfs.go -pkg=main static/...

func NewAssetFS() *assetfs.AssetFS {
	return &assetfs.AssetFS{
		Asset:     Asset,     // generated by go-bindata
		AssetDir:  AssetDir,  // generated by go-bindata
		AssetInfo: AssetInfo, // generated by go-bindata
		Prefix:    "",
	}
}

e.Use(bindata.Static("/static/", NewAssetFS()))

Captcha

Image and audio captcha support.

import "github.com/webx-top/echo/handler/captcha"

captcha.DefaultOptions.Wrapper(e)
// Browse to /captcha/<id>.png

Middleware

// Root level middleware
e.Use(middleware.Log())
e.Use(middleware.Recover())

// Group level middleware
g := e.Group("/admin")
g.Use(middleware.BasicAuth(func(username, password string) bool {
	if username == "joe" && password == "secret" {
		return true
	}
	return false
}))

// Route level middleware
track := func(next echo.HandlerFunc) echo.HandlerFunc {
	return func(c echo.Context) error {
		println("request to /users")
		return next.Handle(c)
	}
}
e.Get("/users", func(c echo.Context) error {
	return c.String("/users", http.StatusOK)
}, track)
e.Get("/setcookie", func(c echo.Context) error {
	c.SetCookie("uid","1")
	return c.String("/setcookie: uid="+c.GetCookie("uid"), http.StatusOK)
})

Session

Session engine supports cookie-based and file-based storage.

...
import (
	...
	"github.com/webx-top/echo/middleware/session"
	cookieStore "github.com/webx-top/echo/middleware/session/engine/cookie"
)
...
sessionOptions := &echo.SessionOptions{
	Engine: `cookie`,
	Name:   `SESSIONID`,
	CookieOptions: &echo.CookieOptions{
		Path:     `/`,
		Domain:   ``,
		MaxAge:   0,
		Secure:   false,
		HttpOnly: true,
	},
}

cookieStore.RegWithOptions(&cookieStore.CookieOptions{
	KeyPairs: [][]byte{
		[]byte(`123456789012345678901234567890ab`),
	},
})

e.Use(session.Middleware(sessionOptions))

e.Get("/session", func(c echo.Context) error {
	c.Session().Set("uid",1).Save()
	return c.String(fmt.Sprintf("/session: uid=%v",c.Session().Get("uid")))
})

Transaction

Supports database transaction through context.

// Transaction interface
type Transaction interface {
	Begin(ctx context.Context) error
	Rollback(ctx context.Context) error
	Commit(ctx context.Context) error
	End(ctx context.Context, succeed bool) error
}

// Use in handler
c.Begin()
// ... operations
c.Commit()

Websocket

...
import (
	...
	"github.com/admpub/websocket"
	"github.com/webx-top/echo"
	ws "github.com/webx-top/echo/handler/websocket"
)
...

e.AddHandlerWrapper(ws.HanderWrapper)

e.Get("/websocket", func(c *websocket.Conn, ctx echo.Context) error {
	//push(writer)
	go func() {
		var counter int
		for {
			if counter >= 10 {
				return
			}
			time.Sleep(5 * time.Second)
			message := time.Now().String()
			ctx.Logger().Info(`Push message: `, message)
			if err := c.WriteMessage(websocket.TextMessage, []byte(message)); err != nil {
				ctx.Logger().Error(`Push error: `, err.Error())
				return
			}
			counter++
		}
	}()

	//echo
	ws.DefaultExecuter(c, ctx)
	return nil
})

More...

Sockjs

...
import (
	...
	"github.com/webx-top/echo"
	"github.com/admpub/sockjs-go/v3/sockjs"
	ws "github.com/webx-top/echo/handler/sockjs"
)
...

options := ws.Options{
	Handle: func(c sockjs.Session) error {
		//push(writer)
		go func() {
			var counter int
			for {
				if counter >= 10 {
					return
				}
				time.Sleep(5 * time.Second)
				message := time.Now().String()
				log.Info(`Push message: `, message)
				if err := c.Send(message); err != nil {
					log.Error(`Push error: `, err.Error())
					return
				}
				counter++
			}
		}()

		//echo
		ws.DefaultExecuter(c)
		return nil
	},
	Options: &sockjs.DefaultOptions,
	Prefix:  "/websocket",
}
options.Wrapper(e)

More...

Server-Sent Events (SSE)

import (
	_ "github.com/webx-top/echo/middleware/render/sse"
	"github.com/webx-top/echo/middleware/render"
)

e.Use(render.Middleware(render.New(`sse`, ``)))

e.Get("/events", func(c echo.Context) error {
	return c.SSEvent("message", listener)
})

Reverse Proxy

Built-in reverse proxy with load balancing support (Random, Round-Robin).

import "github.com/webx-top/echo/middleware"

// Round-Robin balancer
targets := []middleware.ProxyTargeter{
	&middleware.ProxyTarget{
		Name: "api-1",
		URL:  mustParseURL("http://localhost:8081"),
	},
	&middleware.ProxyTarget{
		Name: "api-2",
		URL:  mustParseURL("http://localhost:8082"),
	},
}
balancer := middleware.NewRoundRobinBalancer(targets)
e.Use(middleware.Proxy(balancer))

URL Rewrite

e.Use(middleware.Rewrite(map[string]string{
	"/old":              "/new",
	"/api/*":            "/\$1",
	"/users/:id":        "/user/\$1",
	"/users/*/orders/*": "/user/\$1/order/\$2",
}))

Request Queue

Limit concurrent request processing with queue timeout.

config := middleware.QueueConfig{
	QueueSize:     100,
	Workers:       10,
	QueueTimeout:  30 * time.Second,
	WorkerTimeout: 10 * time.Second,
}
e.Use(middleware.QueueWithConfig(config))

Request ID

e.Use(middleware.RequestID())
// Each response gets X-Request-ID header

IP Filter

import "github.com/webx-top/echo/middleware/ipfilter"

e.Use(ipfilter.IPFilter(ipfilter.Config{
	Options: ipfilter.Options{
		AllowedIPs: []string{"192.168.0.0/24"},
		BlockedIPs: []string{"0.0.0.0/0"},
	},
}))

OpenTracing

import "github.com/webx-top/echo/middleware/opentracing"

e.Use(opentracing.Trace(tracer))

Other Example

package main

import (
	"net/http"

	"github.com/webx-top/echo"
	// "github.com/webx-top/echo/engine/fasthttp"
	"github.com/webx-top/echo/engine/standard"
	mw "github.com/webx-top/echo/middleware"
)

func main() {
	e := echo.New()
	e.Use(mw.Log())

	e.Get("/", func(c echo.Context) error {
		return c.String("Hello, World!")
	})
	e.Get("/echo/:name", func(c echo.Context) error {
		return c.String("Echo " + c.Param("name"))
	})
	
	e.Get("/std", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`standard net/http handleFunc`))
		w.WriteHeader(200)
	})

	// FastHTTP
	// e.Run(fasthttp.New(":4444"))

	// Standard
	e.Run(standard.New(":4444"))
}

See other examples...

Middleware list

Root middleware (github.com/webx-top/echo/middleware)

MiddlewareImport pathDescription
BasicAuthgithub.com/webx-top/echo/middlewareHTTP basic authentication
KeyAuthgithub.com/webx-top/echo/middlewareAPI key authentication (header/query/form)
BodyLimitgithub.com/webx-top/echo/middlewareLimit request body size
Gzipgithub.com/webx-top/echo/middlewareSend gzip HTTP response
Securegithub.com/webx-top/echo/middlewareProtection against XSS, clickjacking, etc
CORSgithub.com/webx-top/echo/middlewareCross-Origin Resource Sharing
CSRFgithub.com/webx-top/echo/middlewareCross-Site Request Forgery
Loggithub.com/webx-top/echo/middlewareLog HTTP requests
MethodOverridegithub.com/webx-top/echo/middlewareOverride request method via header
Recovergithub.com/webx-top/echo/middlewareRecover from panics
HTTPSRedirectgithub.com/webx-top/echo/middlewareRedirect HTTP to HTTPS
HTTPSWWWRedirectgithub.com/webx-top/echo/middlewareRedirect HTTP to WWW HTTPS
WWWRedirectgithub.com/webx-top/echo/middlewareRedirect non-WWW to WWW
NonWWWRedirectgithub.com/webx-top/echo/middlewareRedirect WWW to non-WWW
AddTrailingSlashgithub.com/webx-top/echo/middlewareAdd trailing slash to URI
RemoveTrailingSlashgithub.com/webx-top/echo/middlewareRemove trailing slash from URI
Staticgithub.com/webx-top/echo/middlewareServe static files
MaxAllowedgithub.com/webx-top/echo/middlewareLimit simultaneous requests
NoCachegithub.com/webx-top/echo/middlewareSet no-cache headers
Rewritegithub.com/webx-top/echo/middlewareURL path rewriting
Proxygithub.com/webx-top/echo/middlewareReverse proxy with load balancing
Queuegithub.com/webx-top/echo/middlewareRequest concurrency queue
RequestIDgithub.com/webx-top/echo/middlewareX-Request-ID header
Validategithub.com/webx-top/echo/middlewareRequest validator injection
FuncMapgithub.com/webx-top/echo/middlewareTemplate function map
AJAXgithub.com/webx-top/echo/middlewareAJAX operation handler
Languagegithub.com/webx-top/echo/middleware/languageMulti-language (i18n) support
RateLimitgithub.com/webx-top/echo/middleware/ratelimitRate limiting HTTP requests
RateLimitergithub.com/webx-top/echo/middleware/ratelimiterRate limiter (supports memory & Redis)
Sessiongithub.com/webx-top/echo/middleware/sessionSession manager
JWTgithub.com/webx-top/echo/middleware/jwtJWT authentication
Markdowngithub.com/webx-top/echo/middleware/markdownMarkdown rendering
Rendergithub.com/webx-top/echo/middleware/renderHTML template rendering (standard, Jet, SSE)
IPFiltergithub.com/webx-top/echo/middleware/ipfilterIP address filtering
OpenTracinggithub.com/webx-top/echo/middleware/opentracingDistributed tracing
Bindata Staticgithub.com/webx-top/echo/middleware/bindataServe embedded static files
ReverseProxygithub.com/webx-top/reverseproxyExternal reverse proxy

Handler Wrapper list

WrapperImport pathDescription
Websocketgithub.com/webx-top/echo/handler/websocketExample
Sockjsgithub.com/webx-top/echo/handler/sockjsExample
Oauth2github.com/webx-top/echo/handler/oauth2Example
Pprofgithub.com/webx-top/echo/handler/pprofGo pprof profiler
Captchagithub.com/webx-top/echo/handler/captchaImage & audio captcha
Embedgithub.com/webx-top/echo/handler/embedEmbedded file system file server
SSEgithub.com/webx-top/echo/middleware/render/sseServer-Sent Events render driver

Template Func docs

Template Function Documentation

Template Data

When using the Render middleware, the data passed to c.Render(data) is wrapped into *echo.RenderData. In Go templates, call its exported methods via $.XXX:

{{$.Now}}           {{/* 当前时间 */}}
{{$.UnixTime}}      {{/* 当前时间戳 */}}
{{$.Site}}          {{/* 网站URL */}}
{{$.SiteRoot}}      {{/* 网站根路径 */}}
{{$.URL}}           {{/* 当前请求URL */}}
{{$.URI}}           {{/* 当前请求URI */}}
{{$.Path}}          {{/* 当前请求路径 */}}
{{$.Domain}}        {{/* 当前域名 */}}
{{$.Port}}          {{/* 当前端口 */}}
{{$.Scheme}}        {{/* http/https */}}
{{$.Lang}}          {{/* 当前语言 */}}
{{$.Referer}}       {{/* 来源地址 */}}
{{$.Query "key"}}   {{/* 获取查询参数 */}}
{{$.Form "key"}}    {{/* 获取表单参数 */}}
{{$.Param "key"}}   {{/* 获取路径参数 */}}
{{$.Get "key"}}     {{/* 获取Context中存储的值 */}}
{{$.Cookie}}        {{/* Cookie操作 */}}
{{$.Session}}       {{/* Session操作 */}}
{{$.Flash "key"}}   {{/* Flash消息 */}}
{{$.T "你好%v" "世界"}}  {{/* 多语言翻译 */}}
{{$.LangURI "zh"}}  {{/* 生成语言链接 */}}
{{$.URLByName "routeName" "param1"}}  {{/* 根据路由名生成URL */}}
{{$.CaptchaForm}}   {{/* 验证码表单 */}}
{{$.TimeAgo $time}} {{/* 时间友好显示 */}}
{{$.TsHumanize $time}}{{/* 时间区间友好显示 */}}
{{$.DurationFormat $t}}{{/* 持续时间格式化 */}}
{{$.Fetch "subtmpl" .}}{{/* 渲染子模板并嵌入 */}}
{{$.MakeURL "handler" "arg"}}{{/* 生成URL */}}
{{$.Ext}}           {{/* 默认扩展名 */}}
{{$.ThemeColor}}    {{/* 主题色 */}}
{{$.Prefix}}        {{/* 当前路由前缀 */}}
{{$.RootPrefix}}    {{/* 根路由前缀 */}}
{{$.UploadURL "subdir"}}{{/* 上传文件URL */}}
{{$.FullURL "/path"}}{{/* 生成完整URL */}}
{{$.HasAnyRequest}} {{/* 是否有任何请求数据 */}}
{{$.GetNextURL}}    {{/* 获取跳转URL */}}
{{$.ReturnToCurrentURL}}{{/* 返回当前URL */}}

$.Data is the original data passed to c.Render(), and $.Stored is read-only data set via c.Set("key",any).

Additional Packages

  • formfilter - Form data filtering utilities
  • subdomains - Subdomain routing utilities (with SafeMap)
  • code - Business error code system
  • code/register - Error code registration
  • encoding/dbconfig - Database configuration encoding
  • param - Parameter type utilities (StringSlice, StringMap, Store)
  • testing - HTTP testing utilities
  • mockcontext - Mock context for unit testing
  • defaults - Default configuration utilities
  • logger - Logger integrations

Cases

Credits

License

Apache 2