Comprehensive guide for the Echo web framework. Use when building scalable, high-performance web applications and REST APIs in Go with features like flexible routing, middleware support, request/response binding, static file serving, and template rendering. Applies to installing Echo, defining routes, implementing middleware, handling requests/responses, and building web services.
Inherits all available tools
Additional assets for this skill
This skill inherits all available tools. When active, it can use any tool Claude has access to.
Echo is a high-performance, minimalist Go web framework for building robust REST APIs and web applications with simplicity and efficiency.
Initialize a Go module and install Echo v4:
mkdir myapp && cd myapp
go mod init myapp
go get github.com/labstack/echo/v4
For Go v1.14 or earlier, enable module mode explicitly:
GO111MODULE=on go get github.com/labstack/echo/v4
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.Logger.Fatal(e.Start(":1323"))
}
Run with go run server.go and visit http://localhost:1323.
Define routes using HTTP methods (GET, POST, PUT, DELETE, PATCH, etc.):
e.POST("/users", saveUser)
e.GET("/users/:id", getUser)
e.PUT("/users/:id", updateUser)
e.DELETE("/users/:id", deleteUser)
Extract dynamic segments from URL paths:
func getUser(c echo.Context) error {
id := c.Param("id")
return c.String(http.StatusOK, id)
}
Access query string parameters:
func show(c echo.Context) error {
team := c.QueryParam("team")
member := c.QueryParam("member")
return c.String(http.StatusOK, "team:" + team + ", member:" + member)
}
Echo supports automatic binding of JSON, XML, form, and query data into Go structs:
type User struct {
Name string `json:"name" xml:"name" form:"name" query:"name"`
Email string `json:"email" xml:"email" form:"email" query:"email"`
}
e.POST("/users", func(c echo.Context) error {
u := new(User)
if err := c.Bind(u); err != nil {
return err
}
return c.JSON(http.StatusCreated, u)
})
Handle application/x-www-form-urlencoded requests:
func save(c echo.Context) error {
name := c.FormValue("name")
email := c.FormValue("email")
return c.String(http.StatusOK, "name:" + name + ", email:" + email)
}
Handle multipart form data with file uploads:
func save(c echo.Context) error {
name := c.FormValue("name")
avatar, err := c.FormFile("avatar")
if err != nil {
return err
}
src, err := avatar.Open()
if err != nil {
return err
}
defer src.Close()
dst, err := os.Create(avatar.Filename)
if err != nil {
return err
}
defer dst.Close()
if _, err = io.Copy(dst, src); err != nil {
return err
}
return c.HTML(http.StatusOK, "<b>Thank you! " + name + "</b>")
}
Send structured data as JSON or XML:
e.GET("/users", func(c echo.Context) error {
u := &User{
Name: "Jon",
Email: "[email protected]",
}
return c.JSON(http.StatusOK, u)
// or
// return c.XML(http.StatusOK, u)
})
Format JSON responses for readability:
return c.JSONPretty(http.StatusOK, u, " ")
Map a URL path to a local directory:
e.Static("/static", "assets")
e.Static("/", "public") // serve from root
Serve individual files:
e.File("/", "public/index.html")
e.File("/favicon.ico", "images/favicon.ico")
Serve Single Page Application assets from embedded Go filesystem:
//go:embed web
var webAssets embed.FS
func main() {
e := echo.New()
e.Use(middleware.StaticWithConfig(middleware.StaticConfig{
HTML5: true,
Root: "web",
Filesystem: http.FS(webAssets),
}))
api := e.Group("/api")
api.GET("/users", func(c echo.Context) error {
return c.String(http.StatusOK, "users")
})
if err := e.Start(":8080"); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatal(err)
}
}
Middleware intercepts requests at root, group, or route levels:
Applied to all routes:
e.Use(middleware.Logger())
e.Use(middleware.Recover())
Applied to specific route groups:
g := e.Group("/admin")
g.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) {
if username == "joe" && password == "secret" {
return true, nil
}
return false, nil
}))
Applied to individual routes:
track := func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
println("request to /users")
return next(c)
}
}
e.GET("/users", func(c echo.Context) error {
return c.String(http.StatusOK, "/users")
}, track)
func main() {
e := echo.New()
// add middleware and routes...
if err := e.Start(":8080"); err != http.ErrServerClosed {
log.Fatal(err)
}
}
if err := e.StartTLS(":8443", "server.crt", "server.key"); err != http.ErrServerClosed {
log.Fatal(err)
}
if err := e.StartTLS(":1323", "cert.pem", "key.pem"); err != http.ErrServerClosed {
log.Fatal(err)
}
s := &http2.Server{
MaxConcurrentStreams: 250,
MaxReadFrameSize: 1048576,
IdleTimeout: 10 * time.Second,
}
if err := e.StartH2CServer(":8080", s); err != http.ErrServerClosed {
log.Fatal(err)
}
For advanced configuration:
s := http.Server{
Addr: ":8080",
Handler: e,
//ReadTimeout: 30 * time.Second,
}
if err := s.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
Use session middleware for maintaining user state:
import "github.com/labstack/echo-contrib/session"
import "github.com/gorilla/sessions"
func main() {
e := echo.New()
e.Use(session.Middleware(sessions.NewCookieStore([]byte("secret"))))
e.GET("/create-session", func(c echo.Context) error {
sess, _ := session.Get("session", c)
sess.Values["foo"] = "bar"
sess.Save(c.Request(), c.Response())
return c.NoContent(http.StatusOK)
})
e.GET("/read-session", func(c echo.Context) error {
sess, _ := session.Get("session", c)
return c.String(http.StatusOK, fmt.Sprintf("foo=%v", sess.Values["foo"]))
})
e.Start(":8080")
}
Integrate Prometheus monitoring:
import "github.com/labstack/echo-contrib/echoprometheus"
func main() {
e := echo.New()
e.Use(echoprometheus.NewMiddleware("myapp"))
e.GET("/metrics", echoprometheus.NewHandler())
e.GET("/hello", func(c echo.Context) error {
return c.String(http.StatusOK, "hello")
})
e.Start(":8080")
}
Configure structured logging:
import "go.uber.org/zap"
logger, _ := zap.NewProduction()
e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
LogURI: true,
LogStatus: true,
LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
logger.Info("request",
zap.String("URI", v.URI),
zap.Int("status", v.Status),
)
return nil
},
}))
Export all registered routes as JSON:
routes := e.Routes()
// Each route contains Method, Path, and Name
Context Methods: c.Param(), c.QueryParam(), c.FormValue(), c.FormFile(), c.Bind(), c.String(), c.JSON(), c.XML(), c.HTML(), c.File(), c.Redirect(), c.NoContent()
Echo Methods: e.GET(), e.POST(), e.PUT(), e.DELETE(), e.Static(), e.File(), e.Group(), e.Use(), e.Start(), e.StartTLS(), e.Routes()
echo.Context for request/response manipulation