From 78baf6e38a59edf77bc30c6e0691c19d4a62eaed Mon Sep 17 00:00:00 2001 From: Tamish Mhatre Date: Mon, 13 Jul 2026 11:48:42 +0530 Subject: [PATCH 1/4] docs: add llms.txt for AI-assisted development --- llms.txt | 235 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 llms.txt diff --git a/llms.txt b/llms.txt new file mode 100644 index 000000000..38836e86b --- /dev/null +++ b/llms.txt @@ -0,0 +1,235 @@ +# Echo + +> Echo is a high performance, extensible, minimalist Go web framework built on the standard `net/http` library. The current release line is **v5**, which introduces major breaking changes from v4. Echo adds a fast radix-tree router, request binding with pluggable validator, a deep middleware ecosystem, centralized error handling, and template rendering on top of the standard library. + +Key facts for LLMs: +- Import path is `github.com/labstack/echo/v5` (NOT `github.com/labstack/echo` which is v4) +- Handlers use `*echo.Context` (pointer to struct), NOT `echo.Context` (interface) like v4 +- `Context` is a concrete struct in v5, not an interface +- Logging uses `log/slog`, not the old custom `Logger` interface +- Go 1.25+ required + +## Quick Reference + +- [Echo v5 API Changes](https://github.com/labstack/echo/blob/master/API_CHANGES_V5.md): Complete v4-to-v5 migration guide with all breaking changes +- [Echo Official Docs](https://echo.labstack.com): Human-readable documentation site +- [pkg.go.dev](https://pkg.go.dev/github.com/labstack/echo/v5): API reference on Go package discovery + +## Core Patterns (v5) + +### Server setup + +```go +package main + +import ( + "log/slog" + "net/http" + + "github.com/labstack/echo/v5" + "github.com/labstack/echo/v5/middleware" +) + +func hello(c *echo.Context) error { + return c.String(http.StatusOK, "Hello, World!") +} + +func main() { + e := echo.New() + e.Use(middleware.RequestLogger()) + e.Use(middleware.Recover()) + e.GET("/", hello) + if err := e.Start(":8080"); err != nil { + slog.Error("failed to start server", "error", err) + } +} +``` + +### Handler signature (v5 vs v4) + +```go +// v5 - pointer to struct +func handler(c *echo.Context) error { + return c.JSON(http.StatusOK, map[string]string{"hello": "world"}) +} + +// v4 (DO NOT USE in v5) - interface +func handler(c echo.Context) error { ... } +``` + +### Route registration + +```go +e := echo.New() +e.GET("/users/:id", getUser) +e.POST("/users", createUser) +e.PUT("/users/:id", updateUser) +e.DELETE("/users/:id", deleteUser) + +// Group routes +g := e.Group("/api/v1") +g.GET("/posts", listPosts) +g.POST("/posts", createPost) + +// Group with middleware +admin := e.Group("/admin", middleware.BasicAuth(basicAuthValidator)) +admin.GET("/stats", getStats) +``` + +### Generic parameter extraction (v5 new) + +```go +// Type-safe path params +id, err := echo.PathParam[int](c, "id") +name, err := echo.PathParam[string](c, "name") + +// Query params with defaults +page, err := echo.QueryParamOr[int](c, "page", 1) +tags, err := echo.QueryParams[string](c, "tags") + +// Form values (renamed from FormParam* in v4) +val, err := echo.FormValue[string](c, "field") +val2, err := echo.FormValueOr[string](c, "field", "default") + +// Supported types: bool, string, int/int8/.../int64, uint/.../uint64, +// float32/float64, time.Time, time.Duration +``` + +### Request binding + +```go +type User struct { + Name string `json:"name"` + Email string `json:"email"` +} + +func createUser(c *echo.Context) error { + u := new(User) + if err := c.Bind(u); err != nil { + return echo.NewHTTPError(http.StatusBadRequest, "invalid request body") + } + if err := c.Validate(u); err != nil { + return err + } + return c.JSON(http.StatusCreated, u) +} +``` + +### Error handling (v5 changed) + +```go +// v5 - NewHTTPError takes string, not interface{} +err := echo.NewHTTPError(http.StatusBadRequest, "invalid input") + +// v5 - HTTPErrorHandler signature changed (params swapped, pointer) +e.HTTPErrorHandler = func(c *echo.Context, err error) { + // custom error handling +} + +// v5 - DefaultHTTPErrorHandler is now a factory +e.HTTPErrorHandler = echo.DefaultHTTPErrorHandler(true) // exposeError bool +``` + +### Logging (v5 uses slog) + +```go +// v5 - standard library slog +e.Logger = slog.Default() + +// In handlers +c.Logger().Info("request", "path", c.Path(), "method", c.Request().Method) + +// Custom logger +logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) +e.Logger = logger +``` + +### Middleware + +```go +// Built-in middleware +e.Use(middleware.RequestLogger()) +e.Use(middleware.Recover()) +e.Use(middleware.CORS()) +e.Use(middleware.Gzip()) +e.Use(middleware.BasicAuth(func(c *echo.Context, username, password string) (bool, error) { + return username == "admin" && password == "secret", nil +})) +e.Use(middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(20))) + +// Route-level middleware +e.GET("/sensitive", handler, middleware.RequestID(), middleware.Logger()) +``` + +### Response helpers + +```go +c.String(http.StatusOK, "text") +c.JSON(http.StatusOK, data) +c.JSONPretty(http.StatusOK, data, " ") +c.XML(http.StatusOK, data) +c.Blob(http.StatusOK, "image/png", bytes) +c.Stream(http.StatusOK, "text/event-stream", reader) +c.File("path/to/file") +c.FileFS("file.txt", filesystem) +c.Attachment("path/to/file", "download.txt") +c.Redirect(http.StatusFound, "/new-path") +c.NoContent(http.StatusOK) +c.HTML(http.StatusOK, "

Hello

") +``` + +### Static files + +```go +e.Static("/assets", "public") +e.StaticFS("/static", filesystem) +e.File("/robots.txt", "robots.txt") +e.FileFS("file.txt", filesystem) +``` + +### Context store (v5 type-safe) + +```go +// Set and get values on context +c.Set("user", user) +val, err := echo.ContextGet[*User](c, "user") +count, err := echo.ContextGetOr[int](c, "count", 0) +``` + +### Graceful shutdown with StartConfig (v5 new) + +```go +ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) +defer cancel() + +sc := echo.StartConfig{ + Address: ":8080", + GracefulTimeout: 10 * time.Second, +} +if err := sc.Start(ctx, e); err != nil { + log.Fatal(err) +} +``` + +## v4 to v5 Migration Checklist + +1. Change import from `github.com/labstack/echo` to `github.com/labstack/echo/v5` +2. Change all handler signatures from `echo.Context` to `*echo.Context` +3. Replace custom `Logger` interface with `log/slog` +4. Update `HTTPErrorHandler` signature: `func(c *echo.Context, err error)` (params swapped) +5. `NewHTTPError(code int, message string)` - message is now `string` not `interface{}` +6. `FormParam*` renamed to `FormValue*` +7. `PathParamsBinder` renamed to `PathValuesBinder` +8. `Context.Response()` returns `http.ResponseWriter` instead of `*Response` +9. `ParamNames()`/`ParamValues()` replaced by `PathValues()` +10. Use `StartConfig` for server configuration instead of `Echo` struct fields +11. Route methods return `RouteInfo` instead of `*Route` +12. `Map` type removed - use `map[string]any` directly +13. HTTP method constants removed - use `http.MethodGet`, `http.MethodPost`, etc. +14. `BindPathParams` renamed to `BindPathValues` + +## Optional + +- [Echo GitHub Discussions](https://github.com/labstack/echo/discussions): Community Q&A and proposals +- [Echo Roadmap](https://github.com/labstack/echo/blob/master/ROADMAP.md): Future plans +- [Echo Changelog](https://github.com/labstack/echo/blob/master/CHANGELOG.md): Release history From dd67433c8ba3a662da76418b060302ca4879c50f Mon Sep 17 00:00:00 2001 From: Tamish Mhatre Date: Mon, 13 Jul 2026 11:48:43 +0530 Subject: [PATCH 2/4] docs: add llms-full.txt with complete v5 API reference --- llms-full.txt | 412 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100644 llms-full.txt diff --git a/llms-full.txt b/llms-full.txt new file mode 100644 index 000000000..a0ac51e27 --- /dev/null +++ b/llms-full.txt @@ -0,0 +1,412 @@ +# Echo + +> Echo is a high performance, extensible, minimalist Go web framework built on the standard `net/http` library. The current release line is **v5**, which introduces major breaking changes from v4. Echo adds a fast radix-tree router, request binding with pluggable validator, a deep middleware ecosystem, centralized error handling, and template rendering on top of the standard library. + +Import path: `github.com/labstack/echo/v5` +Go version: 1.25+ +Handler signature: `func(c *echo.Context) error` + +## Critical v5 Breaking Changes + +### 1. Context: interface to struct + +v4: `type Context interface` with handler `func(c echo.Context) error` +v5: `type Context struct` with handler `func(c *echo.Context) error` + +ALL handlers must use `*echo.Context` (pointer). The `Context` type is no longer an interface. + +### 2. Logger: custom interface to slog + +v4: `e.Logger` is a custom `Logger` interface with `Print`, `Debug`, `Info`, etc. +v5: `e.Logger` is `*slog.Logger` from the standard library `log/slog` package. + +```go +e.Logger = slog.Default() +c.Logger().Info("message", "key", "value") +``` + +### 3. HTTPErrorHandler: parameters swapped + +v4: `type HTTPErrorHandler func(err error, c Context)` +v5: `type HTTPErrorHandler func(c *Context, err error)` + +`DefaultHTTPErrorHandler` is now a factory: `echo.DefaultHTTPErrorHandler(exposeError bool) HTTPErrorHandler` + +### 4. HTTPError: message is string + +v4: `NewHTTPError(code int, message ...interface{})` - message is `interface{}` +v5: `NewHTTPError(code int, message string)` - message is `string` + +Added `HTTPError.Wrap(err error)` and `HTTPError.StatusCode()` methods. + +### 5. Router: interface introduced + +v4: `func NewRouter(e *Echo) *Router` / `func (e *Echo) Router() *Router` +v5: `func NewRouter(config RouterConfig) *DefaultRouter` / `func (e *Echo) Router() Router` (returns interface) + +New `Router` interface with `DefaultRouter` implementation. `NewConcurrentRouter(r Router) Router` for thread-safe routing. + +### 6. Route return types + +v4: `e.GET(...)` returns `*Route`, `e.Any(...)` returns `[]*Route`, `e.Routes()` returns `[]*Route` +v5: `e.GET(...)` returns `RouteInfo`, `e.Any(...)` returns `RouteInfo`, new `Routes` type (`[]RouteInfo`) with filtering methods + +```go +type RouteInfo struct { + Name string + Method string + Path string + Parameters []string +} +``` + +`Routes` has `FilterByMethod`, `FilterByName`, `FilterByPath`, `FindByMethodPath`, `Reverse` methods. + +### 7. Response type + +v4: `c.Response()` returns `*Response` +v5: `c.Response()` returns `http.ResponseWriter` + +`Response` struct now embeds `http.ResponseWriter`. `NewResponse` takes `*slog.Logger` instead of `*Echo`. + +### 8. FormParam renamed to FormValue + +v4: `echo.FormParam[T](c Context, key string, ...)` / `FormParamOr` / `FormParams` / `FormParamsOr` +v5: `echo.FormValue[T](c *Context, key string, ...)` / `FormValueOr` / `FormValues` / `FormValuesOr` + +### 9. Removed from Echo struct + +`StdLogger`, `Server`, `TLSServer`, `Listener`, `TLSListener`, `AutoTLSManager`, `ListenerNetwork`, `DisableHTTP2`, `Debug`, `HideBanner`, `HidePort` are all removed. Use `StartConfig` for server configuration. + +### 10. PathParams -> PathValues + +v4: `ParamNames()`, `ParamValues()`, `SetParamNames()`, `SetParamValues()` +v5: `PathValues()` returns `PathValues` type (`[]PathValue`), `SetPathValues(PathValues)` + +### 11. Other renames + +- `PathParamsBinder` -> `PathValuesBinder` +- `BindPathParams` -> `BindPathValues` +- `Map` type removed (use `map[string]any`) +- HTTP method constants removed (use `http.MethodGet`, etc.) +- `GetPath(r *http.Request)` removed (use `r.URL.Path`) + +## Echo struct (v5) + +```go +type Echo struct { + Binder Binder + Filesystem fs.FS + Renderer Renderer + Validator Validator + JSONSerializer JSONSerializer + IPExtractor IPExtractor + OnAddRoute func(route Route) error + HTTPErrorHandler HTTPErrorHandler + Logger *slog.Logger +} +``` + +Constructor: `echo.New() *Echo` or `echo.NewWithConfig(config Config) *Echo` + +## Echo methods + +### Routing + +```go +e.GET(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo +e.POST(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo +e.PUT(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo +e.DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo +e.PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo +e.HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo +e.OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo +e.ANY(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo +e.Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) Routes +e.RouteNotFound(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo +e.AddRoute(route Route) (RouteInfo, error) +``` + +### Middleware + +```go +e.Use(middleware ...MiddlewareFunc) +e.Pre(middleware ...MiddlewareFunc) +e.Middlewares() []MiddlewareFunc +e.PreMiddlewares() []MiddlewareFunc +``` + +### Groups + +```go +e.Group(prefix string, m ...MiddlewareFunc) *Group +``` + +### Static files + +```go +e.Static(pathPrefix, fsRoot string, m ...MiddlewareFunc) RouteInfo +e.StaticFS(pathPrefix string, filesystem fs.FS, m ...MiddlewareFunc) RouteInfo +e.File(path, file string, m ...MiddlewareFunc) RouteInfo +e.FileFS(file string, filesystem fs.FS, m ...MiddlewareFunc) RouteInfo +``` + +### Server + +```go +e.Start(address string) error +e.StartTLS(address string, certFile, keyFile any) error +// v5 also: StartConfig.Start(ctx, handler) and StartConfig.StartTLS(ctx, handler, certFile, keyFile) +``` + +```go +type StartConfig struct { + Address string + HideBanner bool + HidePort bool + CertFilesystem fs.FS + TLSConfig *tls.Config + ListenerNetwork string + ListenerAddrFunc func(addr net.Addr) + GracefulTimeout time.Duration + OnShutdownError func(err error) + BeforeServeFunc func(s *http.Server) error +} +``` + +### Context methods (v5) + +```go +c.Request() *http.Request +c.SetRequest(r *http.Request) +c.Response() http.ResponseWriter +c.SetResponse(rw http.ResponseWriter) +c.IsTLS() bool +c.IsWebSocket() bool +c.Scheme() string +c.RealIP() string +c.Path() string +c.SetPath(path string) +c.RouteInfo() RouteInfo +c.Param(name string) string +c.ParamOr(name, defaultValue string) string +c.PathValues() PathValues +c.SetPathValues(pathValues PathValues) +c.QueryParam(name string) string +c.QueryParamOr(name, defaultValue string) string +c.QueryParams() []string +c.QueryString() string +c.FormValue(name string) string +c.FormValueOr(name, defaultValue string) string +c.FormValues() []string +c.FormFile(name string) (*multipart.FileHeader, error) +c.MultipartForm() (*multipart.Form, error) +c.Cookie(name string) (*http.Cookie, error) +c.SetCookie(cookie *http.Cookie) +c.Cookies() []*http.Cookie +c.Get(key string) any +c.Set(key string, val any) +c.Bind(i any) error +c.Validate(i any) error +c.Render(code int, name string, data any) error +c.HTML(code int, html string) error +c.HTMLBlob(code int, b []byte) error +c.String(code int, s string) error +c.JSON(code int, i any) error +c.JSONPretty(code int, i any, indent string) error +c.JSONBlob(code int, b []byte) error +c.JSONP(code int, callback string, i any) error +c.JSONPBlob(code int, callback string, i any) error +c.XML(code int, i any) error +c.XMLPretty(code int, i any, indent string) error +c.XMLBlob(code int, b []byte) error +c.Blob(code int, contentType string, b []byte) error +c.Stream(code int, contentType string, r io.Reader) error +c.File(file string) error +c.FileFS(file string, filesystem fs.FS) error +c.Attachment(file, name string) error +c.Inline(file, name string) error +c.NoContent(code int) error +c.Redirect(code int, url string) error +c.Logger() *slog.Logger +c.SetLogger(logger *slog.Logger) +c.Echo() *Echo +``` + +### Generic helper functions (v5) + +```go +echo.PathParam[T](c *Context, name string, opts ...any) (T, error) +echo.PathParamOr[T](c *Context, name string, defaultValue T, opts ...any) (T, error) +echo.QueryParam[T](c *Context, key string, opts ...any) (T, error) +echo.QueryParamOr[T](c *Context, key string, defaultValue T, opts ...any) (T, error) +echo.QueryParams[T](c *Context, key string, opts ...any) ([]T, error) +echo.QueryParamsOr[T](c *Context, key string, defaultValue []T, opts ...any) ([]T, error) +echo.FormValue[T](c *Context, key string, opts ...any) (T, error) +echo.FormValueOr[T](c *Context, key string, defaultValue T, opts ...any) (T, error) +echo.FormValues[T](c *Context, key string, opts ...any) ([]T, error) +echo.FormValuesOr[T](c *Context, key string, defaultValue []T, opts ...any) ([]T, error) +echo.ParseValue[T](value string, opts ...any) (T, error) +echo.ParseValueOr[T](value string, defaultValue T, opts ...any) (T, error) +echo.ParseValues[T](values []string, opts ...any) ([]T, error) +echo.ParseValuesOr[T](values []string, defaultValue []T, opts ...any) ([]T, error) +echo.ContextGet[T](c *Context, key string) (T, error) +echo.ContextGetOr[T](c *Context, key string, defaultValue T) (T, error) +``` + +Supported generic types: bool, string, int/int8/int16/int32/int64, uint/uint8/uint16/uint32/uint64, float32/float64, time.Time, time.Duration, BindUnmarshaler, encoding.TextUnmarshaler, json.Unmarshaler + +### Binding functions (v5) + +```go +echo.BindBody(c *Context, target any) error +echo.BindHeaders(c *Context, target any) error +echo.BindPathValues(c *Context, target any) error +echo.BindQueryParams(c *Context, target any) error +``` + +### Binder helpers (v5) + +```go +echo.PathValuesBinder(c *Context) *ValueBinder +echo.QueryParamsBinder(c *Context) *ValueBinder +echo.FormFieldBinder(c *Context) *ValueBinder +``` + +### Wrapping stdlib handlers + +```go +echo.WrapHandler(h http.Handler) HandlerFunc +echo.WrapMiddleware(m func(http.Handler) http.Handler) MiddlewareFunc +``` + +## Group methods + +```go +g.Use(m ...MiddlewareFunc) +g.Group(prefix string, m ...MiddlewareFunc) *Group +g.GET(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo +g.POST(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo +g.PUT(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo +g.DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo +g.PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo +g.ANY(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo +g.Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) Routes +g.Static(pathPrefix, fsRoot string, m ...MiddlewareFunc) RouteInfo +g.StaticFS(pathPrefix string, filesystem fs.FS, m ...MiddlewareFunc) RouteInfo +g.File(path, file string, m ...MiddlewareFunc) RouteInfo +g.FileFS(file string, filesystem fs.FS, m ...MiddlewareFunc) RouteInfo +``` + +## Built-in middleware + +| Middleware | Description | +|---|---| +| BasicAuth | HTTP basic authentication | +| BodyDump | Dumps request and response bodies | +| BodyLimit | Limits request body size | +| Compress | Gzip response compression | +| ContextTimeout | Request context timeout | +| CORS | Cross-origin resource sharing | +| CSRF | Cross-site request forgery protection | +| Decompress | Gzip request decompression | +| KeyAuth | Key-based authentication | +| MethodOverride | HTTP method override | +| Proxy | Reverse proxy | +| RateLimiter | Rate limiting | +| Recover | Panic recovery | +| Redirect | HTTP redirect | +| RequestID | Request ID header | +| RequestLogger | Structured request logging | +| Rewrite | URL rewriting | +| Secure | Security headers | +| Slash | Trailing slash handling | +| Static | Static file serving | + +## PathValues type (v5) + +```go +type PathValue struct { + Name string + Value string +} +type PathValues []PathValue + +func (p PathValues) Get(name string) (string, bool) +func (p PathValues) GetOr(name string, defaultValue string) string +``` + +## echotest package (v5 new) + +```go +import "github.com/labstack/echo/v5/echotest" + +echotest.LoadBytes(t *testing.T, name string, opts ...loadBytesOpts) []byte +echotest.TrimNewlineEnd(bytes []byte) []byte +echotest.ContextConfig{...} +echotest.MultipartForm{...} +echotest.MultipartFormFile{...} +``` + +## Error variables (v5) + +```go +echo.ErrBadRequest +echo.ErrValidatorNotRegistered +echo.ErrInvalidKeyType +echo.ErrNonExistentKey +``` + +## Virtual host (v5 new) + +```go +echo.NewVirtualHostHandler(vhosts map[string]*Echo) *Echo +``` + +## Complete server example with graceful shutdown + +```go +package main + +import ( + "context" + "log/slog" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + "github.com/labstack/echo/v5" + "github.com/labstack/echo/v5/middleware" +) + +func main() { + e := echo.New() + e.Use(middleware.RequestLogger()) + e.Use(middleware.Recover()) + + e.GET("/", func(c *echo.Context) error { + return c.String(http.StatusOK, "Hello, World!") + }) + + e.GET("/users/:id", func(c *echo.Context) error { + id, err := echo.PathParam[int](c, "id") + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, "invalid user id") + } + return c.JSON(http.StatusOK, map[string]int{"id": id}) + }) + + ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer cancel() + + sc := echo.StartConfig{ + Address: ":8080", + GracefulTimeout: 10 * time.Second, + } + if err := sc.Start(ctx, e); err != nil { + slog.Error("server error", "error", err) + } +} +``` From 42dcc597ab589a98a63c89d7a28ec9b29b667232 Mon Sep 17 00:00:00 2001 From: Tamish Mhatre Date: Tue, 14 Jul 2026 01:55:00 +0530 Subject: [PATCH 3/4] docs: rework llms.txt to describe v5 without migration focus --- llms.txt | 60 +++++++++++++++++++------------------------------------- 1 file changed, 20 insertions(+), 40 deletions(-) diff --git a/llms.txt b/llms.txt index 38836e86b..7071adcf8 100644 --- a/llms.txt +++ b/llms.txt @@ -1,21 +1,21 @@ # Echo -> Echo is a high performance, extensible, minimalist Go web framework built on the standard `net/http` library. The current release line is **v5**, which introduces major breaking changes from v4. Echo adds a fast radix-tree router, request binding with pluggable validator, a deep middleware ecosystem, centralized error handling, and template rendering on top of the standard library. +> Echo is a high performance, extensible, minimalist Go web framework built on the standard `net/http` library. Echo adds a fast radix-tree router, request binding with pluggable validator, a deep middleware ecosystem, centralized error handling, and template rendering on top of the standard library. Key facts for LLMs: -- Import path is `github.com/labstack/echo/v5` (NOT `github.com/labstack/echo` which is v4) -- Handlers use `*echo.Context` (pointer to struct), NOT `echo.Context` (interface) like v4 -- `Context` is a concrete struct in v5, not an interface -- Logging uses `log/slog`, not the old custom `Logger` interface +- Import path is `github.com/labstack/echo/v5` +- Handlers use `*echo.Context` (pointer to struct) +- `Context` is a concrete struct, not an interface +- Logging uses `log/slog` - Go 1.25+ required ## Quick Reference -- [Echo v5 API Changes](https://github.com/labstack/echo/blob/master/API_CHANGES_V5.md): Complete v4-to-v5 migration guide with all breaking changes +- [Echo v5 API Changes](https://github.com/labstack/echo/blob/master/API_CHANGES_V5.md): Breaking changes reference - [Echo Official Docs](https://echo.labstack.com): Human-readable documentation site - [pkg.go.dev](https://pkg.go.dev/github.com/labstack/echo/v5): API reference on Go package discovery -## Core Patterns (v5) +## Core Patterns ### Server setup @@ -45,16 +45,12 @@ func main() { } ``` -### Handler signature (v5 vs v4) +### Handler signature ```go -// v5 - pointer to struct func handler(c *echo.Context) error { return c.JSON(http.StatusOK, map[string]string{"hello": "world"}) } - -// v4 (DO NOT USE in v5) - interface -func handler(c echo.Context) error { ... } ``` ### Route registration @@ -76,7 +72,7 @@ admin := e.Group("/admin", middleware.BasicAuth(basicAuthValidator)) admin.GET("/stats", getStats) ``` -### Generic parameter extraction (v5 new) +### Generic parameter extraction ```go // Type-safe path params @@ -87,7 +83,7 @@ name, err := echo.PathParam[string](c, "name") page, err := echo.QueryParamOr[int](c, "page", 1) tags, err := echo.QueryParams[string](c, "tags") -// Form values (renamed from FormParam* in v4) +// Form values val, err := echo.FormValue[string](c, "field") val2, err := echo.FormValueOr[string](c, "field", "default") @@ -115,25 +111,25 @@ func createUser(c *echo.Context) error { } ``` -### Error handling (v5 changed) +### Error handling ```go -// v5 - NewHTTPError takes string, not interface{} +// NewHTTPError takes a string message err := echo.NewHTTPError(http.StatusBadRequest, "invalid input") -// v5 - HTTPErrorHandler signature changed (params swapped, pointer) +// Custom error handler e.HTTPErrorHandler = func(c *echo.Context, err error) { // custom error handling } -// v5 - DefaultHTTPErrorHandler is now a factory -e.HTTPErrorHandler = echo.DefaultHTTPErrorHandler(true) // exposeError bool +// DefaultHTTPErrorHandler is a factory (exposeError bool) +e.HTTPErrorHandler = echo.DefaultHTTPErrorHandler(true) ``` -### Logging (v5 uses slog) +### Logging ```go -// v5 - standard library slog +// Echo uses the standard library slog e.Logger = slog.Default() // In handlers @@ -187,7 +183,7 @@ e.File("/robots.txt", "robots.txt") e.FileFS("file.txt", filesystem) ``` -### Context store (v5 type-safe) +### Context store (type-safe) ```go // Set and get values on context @@ -196,7 +192,7 @@ val, err := echo.ContextGet[*User](c, "user") count, err := echo.ContextGetOr[int](c, "count", 0) ``` -### Graceful shutdown with StartConfig (v5 new) +### Graceful shutdown with StartConfig ```go ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) @@ -211,25 +207,9 @@ if err := sc.Start(ctx, e); err != nil { } ``` -## v4 to v5 Migration Checklist - -1. Change import from `github.com/labstack/echo` to `github.com/labstack/echo/v5` -2. Change all handler signatures from `echo.Context` to `*echo.Context` -3. Replace custom `Logger` interface with `log/slog` -4. Update `HTTPErrorHandler` signature: `func(c *echo.Context, err error)` (params swapped) -5. `NewHTTPError(code int, message string)` - message is now `string` not `interface{}` -6. `FormParam*` renamed to `FormValue*` -7. `PathParamsBinder` renamed to `PathValuesBinder` -8. `Context.Response()` returns `http.ResponseWriter` instead of `*Response` -9. `ParamNames()`/`ParamValues()` replaced by `PathValues()` -10. Use `StartConfig` for server configuration instead of `Echo` struct fields -11. Route methods return `RouteInfo` instead of `*Route` -12. `Map` type removed - use `map[string]any` directly -13. HTTP method constants removed - use `http.MethodGet`, `http.MethodPost`, etc. -14. `BindPathParams` renamed to `BindPathValues` - ## Optional - [Echo GitHub Discussions](https://github.com/labstack/echo/discussions): Community Q&A and proposals - [Echo Roadmap](https://github.com/labstack/echo/blob/master/ROADMAP.md): Future plans - [Echo Changelog](https://github.com/labstack/echo/blob/master/CHANGELOG.md): Release history +- [API_CHANGES_V5.md](https://github.com/labstack/echo/blob/master/API_CHANGES_V5.md): Full v5 breaking changes reference From 08bf230e07c0b28795f286ad82083751eb29c673 Mon Sep 17 00:00:00 2001 From: Tamish Mhatre Date: Tue, 14 Jul 2026 01:55:01 +0530 Subject: [PATCH 4/4] docs: rework llms-full.txt to describe v5 api without v4 comparisons --- llms-full.txt | 321 ++++++++++++++++++++++++-------------------------- 1 file changed, 155 insertions(+), 166 deletions(-) diff --git a/llms-full.txt b/llms-full.txt index a0ac51e27..b6db08055 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -1,97 +1,90 @@ # Echo -> Echo is a high performance, extensible, minimalist Go web framework built on the standard `net/http` library. The current release line is **v5**, which introduces major breaking changes from v4. Echo adds a fast radix-tree router, request binding with pluggable validator, a deep middleware ecosystem, centralized error handling, and template rendering on top of the standard library. +> Echo is a high performance, extensible, minimalist Go web framework built on the standard `net/http` library. Echo adds a fast radix-tree router, request binding with pluggable validator, a deep middleware ecosystem, centralized error handling, and template rendering on top of the standard library. Import path: `github.com/labstack/echo/v5` Go version: 1.25+ Handler signature: `func(c *echo.Context) error` -## Critical v5 Breaking Changes +## Context -### 1. Context: interface to struct +`Context` is a concrete struct passed by pointer to all handlers. -v4: `type Context interface` with handler `func(c echo.Context) error` -v5: `type Context struct` with handler `func(c *echo.Context) error` - -ALL handlers must use `*echo.Context` (pointer). The `Context` type is no longer an interface. +```go +type Context struct { ... } -### 2. Logger: custom interface to slog +// Handlers receive *echo.Context +func handler(c *echo.Context) error { ... } +``` -v4: `e.Logger` is a custom `Logger` interface with `Print`, `Debug`, `Info`, etc. -v5: `e.Logger` is `*slog.Logger` from the standard library `log/slog` package. +### Context methods ```go -e.Logger = slog.Default() -c.Logger().Info("message", "key", "value") +c.Request() *http.Request +c.SetRequest(r *http.Request) +c.Response() http.ResponseWriter +c.SetResponse(rw http.ResponseWriter) +c.IsTLS() bool +c.IsWebSocket() bool +c.Scheme() string +c.RealIP() string +c.Path() string +c.SetPath(path string) +c.RouteInfo() RouteInfo +c.Param(name string) string +c.ParamOr(name, defaultValue string) string +c.PathValues() PathValues +c.SetPathValues(pathValues PathValues) +c.QueryParam(name string) string +c.QueryParamOr(name, defaultValue string) string +c.QueryParams() []string +c.QueryString() string +c.FormValue(name string) string +c.FormValueOr(name, defaultValue string) string +c.FormValues() []string +c.FormFile(name string) (*multipart.FileHeader, error) +c.MultipartForm() (*multipart.Form, error) +c.Cookie(name string) (*http.Cookie, error) +c.SetCookie(cookie *http.Cookie) +c.Cookies() []*http.Cookie +c.Get(key string) any +c.Set(key string, val any) +c.Bind(i any) error +c.Validate(i any) error +c.Render(code int, name string, data any) error +c.HTML(code int, html string) error +c.HTMLBlob(code int, b []byte) error +c.String(code int, s string) error +c.JSON(code int, i any) error +c.JSONPretty(code int, i any, indent string) error +c.JSONBlob(code int, b []byte) error +c.JSONP(code int, callback string, i any) error +c.JSONPBlob(code int, callback string, i any) error +c.XML(code int, i any) error +c.XMLPretty(code int, i any, indent string) error +c.XMLBlob(code int, b []byte) error +c.Blob(code int, contentType string, b []byte) error +c.Stream(code int, contentType string, r io.Reader) error +c.File(file string) error +c.FileFS(file string, filesystem fs.FS) error +c.Attachment(file, name string) error +c.Inline(file, name string) error +c.NoContent(code int) error +c.Redirect(code int, url string) error +c.Logger() *slog.Logger +c.SetLogger(logger *slog.Logger) +c.Echo() *Echo ``` -### 3. HTTPErrorHandler: parameters swapped - -v4: `type HTTPErrorHandler func(err error, c Context)` -v5: `type HTTPErrorHandler func(c *Context, err error)` - -`DefaultHTTPErrorHandler` is now a factory: `echo.DefaultHTTPErrorHandler(exposeError bool) HTTPErrorHandler` - -### 4. HTTPError: message is string - -v4: `NewHTTPError(code int, message ...interface{})` - message is `interface{}` -v5: `NewHTTPError(code int, message string)` - message is `string` - -Added `HTTPError.Wrap(err error)` and `HTTPError.StatusCode()` methods. - -### 5. Router: interface introduced - -v4: `func NewRouter(e *Echo) *Router` / `func (e *Echo) Router() *Router` -v5: `func NewRouter(config RouterConfig) *DefaultRouter` / `func (e *Echo) Router() Router` (returns interface) - -New `Router` interface with `DefaultRouter` implementation. `NewConcurrentRouter(r Router) Router` for thread-safe routing. - -### 6. Route return types - -v4: `e.GET(...)` returns `*Route`, `e.Any(...)` returns `[]*Route`, `e.Routes()` returns `[]*Route` -v5: `e.GET(...)` returns `RouteInfo`, `e.Any(...)` returns `RouteInfo`, new `Routes` type (`[]RouteInfo`) with filtering methods +### Context store (type-safe) ```go -type RouteInfo struct { - Name string - Method string - Path string - Parameters []string -} +c.Set("user", user) +val, err := echo.ContextGet[*User](c, "user") +count, err := echo.ContextGetOr[int](c, "count", 0) ``` -`Routes` has `FilterByMethod`, `FilterByName`, `FilterByPath`, `FindByMethodPath`, `Reverse` methods. - -### 7. Response type - -v4: `c.Response()` returns `*Response` -v5: `c.Response()` returns `http.ResponseWriter` - -`Response` struct now embeds `http.ResponseWriter`. `NewResponse` takes `*slog.Logger` instead of `*Echo`. - -### 8. FormParam renamed to FormValue - -v4: `echo.FormParam[T](c Context, key string, ...)` / `FormParamOr` / `FormParams` / `FormParamsOr` -v5: `echo.FormValue[T](c *Context, key string, ...)` / `FormValueOr` / `FormValues` / `FormValuesOr` - -### 9. Removed from Echo struct - -`StdLogger`, `Server`, `TLSServer`, `Listener`, `TLSListener`, `AutoTLSManager`, `ListenerNetwork`, `DisableHTTP2`, `Debug`, `HideBanner`, `HidePort` are all removed. Use `StartConfig` for server configuration. - -### 10. PathParams -> PathValues - -v4: `ParamNames()`, `ParamValues()`, `SetParamNames()`, `SetParamValues()` -v5: `PathValues()` returns `PathValues` type (`[]PathValue`), `SetPathValues(PathValues)` - -### 11. Other renames - -- `PathParamsBinder` -> `PathValuesBinder` -- `BindPathParams` -> `BindPathValues` -- `Map` type removed (use `map[string]any`) -- HTTP method constants removed (use `http.MethodGet`, etc.) -- `GetPath(r *http.Request)` removed (use `r.URL.Path`) - -## Echo struct (v5) +## Echo struct ```go type Echo struct { @@ -156,7 +149,6 @@ e.FileFS(file string, filesystem fs.FS, m ...MiddlewareFunc) RouteInfo ```go e.Start(address string) error e.StartTLS(address string, certFile, keyFile any) error -// v5 also: StartConfig.Start(ctx, handler) and StartConfig.StartTLS(ctx, handler, certFile, keyFile) ``` ```go @@ -172,68 +164,87 @@ type StartConfig struct { OnShutdownError func(err error) BeforeServeFunc func(s *http.Server) error } + +// StartConfig.Start and StartConfig.StartTLS for graceful shutdown +sc := echo.StartConfig{Address: ":8080", GracefulTimeout: 10 * time.Second} +sc.Start(ctx, e) ``` -### Context methods (v5) +## Error handling ```go -c.Request() *http.Request -c.SetRequest(r *http.Request) -c.Response() http.ResponseWriter -c.SetResponse(rw http.ResponseWriter) -c.IsTLS() bool -c.IsWebSocket() bool -c.Scheme() string -c.RealIP() string -c.Path() string -c.SetPath(path string) -c.RouteInfo() RouteInfo -c.Param(name string) string -c.ParamOr(name, defaultValue string) string -c.PathValues() PathValues -c.SetPathValues(pathValues PathValues) -c.QueryParam(name string) string -c.QueryParamOr(name, defaultValue string) string -c.QueryParams() []string -c.QueryString() string -c.FormValue(name string) string -c.FormValueOr(name, defaultValue string) string -c.FormValues() []string -c.FormFile(name string) (*multipart.FileHeader, error) -c.MultipartForm() (*multipart.Form, error) -c.Cookie(name string) (*http.Cookie, error) -c.SetCookie(cookie *http.Cookie) -c.Cookies() []*http.Cookie -c.Get(key string) any -c.Set(key string, val any) -c.Bind(i any) error -c.Validate(i any) error -c.Render(code int, name string, data any) error -c.HTML(code int, html string) error -c.HTMLBlob(code int, b []byte) error -c.String(code int, s string) error -c.JSON(code int, i any) error -c.JSONPretty(code int, i any, indent string) error -c.JSONBlob(code int, b []byte) error -c.JSONP(code int, callback string, i any) error -c.JSONPBlob(code int, callback string, i any) error -c.XML(code int, i any) error -c.XMLPretty(code int, i any, indent string) error -c.XMLBlob(code int, b []byte) error -c.Blob(code int, contentType string, b []byte) error -c.Stream(code int, contentType string, r io.Reader) error -c.File(file string) error -c.FileFS(file string, filesystem fs.FS) error -c.Attachment(file, name string) error -c.Inline(file, name string) error -c.NoContent(code int) error -c.Redirect(code int, url string) error -c.Logger() *slog.Logger -c.SetLogger(logger *slog.Logger) -c.Echo() *Echo +// HTTPError with string message +err := echo.NewHTTPError(http.StatusBadRequest, "invalid input") + +// Custom error handler (params: context pointer, then error) +e.HTTPErrorHandler = func(c *echo.Context, err error) { + // custom error handling +} + +// Default error handler factory (exposeError bool) +e.HTTPErrorHandler = echo.DefaultHTTPErrorHandler(true) +``` + +```go +echo.ErrBadRequest +echo.ErrValidatorNotRegistered +echo.ErrInvalidKeyType +echo.ErrNonExistentKey +``` + +## Logging + +Echo uses the standard library `log/slog` package. + +```go +e.Logger = slog.Default() +c.Logger().Info("message", "key", "value") + +// Custom logger +logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) +e.Logger = logger +``` + +## Router + +```go +// Router interface with DefaultRouter implementation +func NewRouter(config RouterConfig) *DefaultRouter +func (e *Echo) Router() Router + +// Thread-safe routing +func NewConcurrentRouter(r Router) Router ``` -### Generic helper functions (v5) +## RouteInfo + +```go +type RouteInfo struct { + Name string + Method string + Path string + Parameters []string +} + +// Routes type with filtering methods +type Routes []RouteInfo +// Methods: FilterByMethod, FilterByName, FilterByPath, FindByMethodPath, Reverse +``` + +## PathValues + +```go +type PathValue struct { + Name string + Value string +} +type PathValues []PathValue + +func (p PathValues) Get(name string) (string, bool) +func (p PathValues) GetOr(name string, defaultValue string) string +``` + +## Generic helper functions ```go echo.PathParam[T](c *Context, name string, opts ...any) (T, error) @@ -256,7 +267,7 @@ echo.ContextGetOr[T](c *Context, key string, defaultValue T) (T, error) Supported generic types: bool, string, int/int8/int16/int32/int64, uint/uint8/uint16/uint32/uint64, float32/float64, time.Time, time.Duration, BindUnmarshaler, encoding.TextUnmarshaler, json.Unmarshaler -### Binding functions (v5) +## Binding functions ```go echo.BindBody(c *Context, target any) error @@ -265,7 +276,7 @@ echo.BindPathValues(c *Context, target any) error echo.BindQueryParams(c *Context, target any) error ``` -### Binder helpers (v5) +### Binder helpers ```go echo.PathValuesBinder(c *Context) *ValueBinder @@ -273,13 +284,6 @@ echo.QueryParamsBinder(c *Context) *ValueBinder echo.FormFieldBinder(c *Context) *ValueBinder ``` -### Wrapping stdlib handlers - -```go -echo.WrapHandler(h http.Handler) HandlerFunc -echo.WrapMiddleware(m func(http.Handler) http.Handler) MiddlewareFunc -``` - ## Group methods ```go @@ -323,20 +327,20 @@ g.FileFS(file string, filesystem fs.FS, m ...MiddlewareFunc) RouteInfo | Slash | Trailing slash handling | | Static | Static file serving | -## PathValues type (v5) +## Wrapping stdlib handlers ```go -type PathValue struct { - Name string - Value string -} -type PathValues []PathValue +echo.WrapHandler(h http.Handler) HandlerFunc +echo.WrapMiddleware(m func(http.Handler) http.Handler) MiddlewareFunc +``` -func (p PathValues) Get(name string) (string, bool) -func (p PathValues) GetOr(name string, defaultValue string) string +## Virtual host + +```go +echo.NewVirtualHostHandler(vhosts map[string]*Echo) *Echo ``` -## echotest package (v5 new) +## echotest package ```go import "github.com/labstack/echo/v5/echotest" @@ -348,22 +352,7 @@ echotest.MultipartForm{...} echotest.MultipartFormFile{...} ``` -## Error variables (v5) - -```go -echo.ErrBadRequest -echo.ErrValidatorNotRegistered -echo.ErrInvalidKeyType -echo.ErrNonExistentKey -``` - -## Virtual host (v5 new) - -```go -echo.NewVirtualHostHandler(vhosts map[string]*Echo) *Echo -``` - -## Complete server example with graceful shutdown +## Complete server example ```go package main