Echo Web Framework

website·Indexed 35 days ago

https://echo.labstack.com/

A high-performance web framework for Go (distributed as github.com/labstack/echo/v5). It provides a robust set of tools for HTTP request handling, including data binding, template rendering, and a comprehensive suite of middleware for session management, CSRF protection, JWT authentication, and request logging.

Tokens
32.1K
Snippets
191
Records
211
Agent score
71%

What's inside Echo

  1. Overview of the Echo Go web framework

    Echo is a high-performance, minimalist Go web framework designed for building fast APIs without bloat. Key features include a radix-tree router with zero dynamic allocation per request, over 25 built-in middlewares (including CORS, JWT, rate-limiting, and gzip), data binding for JSON/XML/form/query/path parameters into typed structs, and native support for Automatic TLS via Let's Encrypt and HTTP/2.
  2. Configure the RequestLogger middleware

    The RequestLogger middleware logs information about each HTTP request. It is highly customizable via the RequestLoggerConfig struct. To populate a specific value in the RequestLoggerValues object passed to the LogValuesFunc, the corresponding boolean flag in the configuration must be set to true (e.g., LogStatus: true).

    Key configuration options include:

    • LogValuesFunc: (Mandatory) The callback function where the actual logging logic resides.
    • Skipper: A function to determine if the middleware should be skipped for a specific request.
    • BeforeNextFunc: A function called before the next middleware or handler in the chain.
    • HandleError: If true, instructs the logger to call the global error handler when the next handler returns an error.
    • LogLatency, LogProtocol, LogRemoteIP, LogHost, LogMethod, LogURI, LogURIPath, LogRoutePath, LogRequestID, LogReferer, LogUserAgent, LogStatus, LogError, LogContentLength, LogResponseSize: Boolean flags to enable extraction of specific request/response metadata.
    • LogHeaders, LogQueryParams, LogFormValues: Slices of strings specifying which headers, query parameters, or form values to extract.
    import "github.com/labstack/echo/v5/middleware"
    
    _ = middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
        LogStatus: true,
        LogURI:    true,
        LogValuesFunc: func(c *echo.Context, v middleware.RequestLoggerValues) error {
            // Logging logic here
            return nil
        },
    })
    
  3. Understand the role of echo.Context

    echo.Context represents the context of the current HTTP request. A pointer to it (*echo.Context) is passed to every handler and middleware, providing access to the request and response, path parameters, bound data, and helper methods for building responses.
    func handler(c *echo.Context) error {
      // ...
      return nil
    }
  4. Update Echo v5 to the latest version

    Keep Echo up to date by fetching the latest version of the module and cleaning up the dependencies using go mod tidy.
    go get github.com/labstack/echo/v5
    go mod tidy
  5. Implement a custom binder in Echo

    You can override the default binding behavior by implementing the Bind method on a custom struct and assigning it to e.Binder. This is useful for adding custom decoding logic or handling specific media types.
    type CustomBinder struct{}
    
    func (cb *CustomBinder) Bind(c *echo.Context, i any) error {
        db := new(echo.DefaultBinder)
        if err := db.Bind(c, i); err != echo.ErrUnsupportedMediaType {
            return err
        }
        // custom logic here
        return nil
    }
    
    e.Binder = &CustomBinder{}
  6. Implement HTTP/2 Server Push in Echo

    HTTP/2 server push allows a server to send resources (like CSS, JS, and images) to the client before they are explicitly requested, reducing round trips. To implement this in Echo, you must unwrap the response to access the underlying http.ResponseWriter and check if it implements the http.Pusher interface.
    e.GET("/", func(c *echo.Context) (err error) {
        // Unwrap the response to access the underlying http.ResponseWriter
        rw, err := echo.UnwrapResponse(c.Response())
        if err != nil {
            return
        }
    
        // Check if the writer implements http.Pusher
        if pusher, ok := rw.ResponseWriter.(http.Pusher); ok {
            if err = pusher.Push("/app.css", nil); err != nil {
                return
            }
            if err = pusher.Push("/app.js", nil); err != nil {
                return
            }
            if err = pusher.Push("/echo.png", nil); err != nil {
                return
            }
        }
        return c.File("index.html")
    })
    
  7. Access the CSRF token in handlers

    The generated CSRF token can be accessed in two ways:

    • Server-side: The token is stored in the echo.Context under the key defined by ContextKey (default is "csrf"). This allows it to be passed to HTML templates.
    • Client-side: The token can be read directly from the CSRF cookie (default name _csrf).
  8. Implement request data validation in Echo

    Echo does not have built-in validation. To validate data, register a custom validator by assigning a struct that implements a Validate(i any) error method to Echo#Validator. This is commonly used with third-party libraries like go-playground/validator.
    package main
    import (
      "net/http"
      "github.com/go-playground/validator/v10"
      "github.com/labstack/echo/v5"
    )
    
    type CustomValidator struct {
      validator *validator.Validate
    }
    
    func (cv *CustomValidator) Validate(i any) error {
      if err := cv.validator.Struct(i); err != nil {
        return echo.ErrBadRequest.Wrap(err)
      }
      return nil
    }
    
    type User struct {
      Name  string `json:"name" validate:"required"` 
      Email string `json:"email" validate:"required,email"`
    }
    
    func main() {
      e := echo.New()
      e.Validator = &CustomValidator{validator: validator.New()}
    
      e.POST("/users", func(c *echo.Context) error {
        u := new(User)
        if err := c.Bind(u); err != nil {
          return err
        }
        if err := c.Validate(u); err != nil {
          return err
        }
        return c.JSON(http.StatusOK, u)
      })
      e.Start(":1323")
    }
  9. Rewrite proxy request URLs using patterns and regex

    The Proxy middleware supports two types of URL rewriting: simple pattern-based rewrites and regular expression-based rewrites. Both can be used simultaneously. In both cases, captured groups are referenced in the replacement string using $1, $2, etc.
    e.Use(middleware.ProxyWithConfig(middleware.ProxyConfig{
        Balancer: rrb,
        // Simple pattern rewrite: /api/users -> /v2/users
        Rewrite: map[string]string{
            "/api/*": "/v2/$1",
        },
        // Regex rewrite: /foo/123 -> /num/123
        RegexRewrite: map[*regexp.Regexp]string{
            regexp.MustCompile("^/foo/([0-9].*)"): "/num/$1",
            regexp.MustCompile("^/bar/(.+?)/(.*)"): "/baz/$2/$1",
        },
    }))
  10. Redirect non-WWW requests to WWW

    Use the WWWRedirect middleware to redirect requests from a non-www domain to the www version of the same protocol (e.g., http://labstack.com becomes http://www.labstack.com).
    import "github.com/labstack/echo/v5/middleware"
    
    e := echo.New()
    e.Pre(middleware.WWWRedirect())
  11. Bind request data to a struct using c.Bind()

    Echo allows parsing request data from URL path parameters, URL query parameters, headers, and the request body into a Go struct using c.Bind(). You must pass a pointer to the struct. Path, query, header, and form fields require explicit struct tags. JSON and XML fall back to the struct field name if the tag is omitted.
    type User struct {
        ID string `query:"id"`
    }
    
    // handler for /users?id=<userID>
    var user User
    if err := c.Bind(&user); err != nil {
        return c.String(http.StatusBadRequest, "bad request")
    }