Skip to main content
echo Echo framework guardrails, patterns, and best practices for AI-assisted development.
Use when working with Echo projects, or when the user mentions Echo framework.
Provides middleware patterns, routing, context handling, and REST API guidelines.
跳到安装 Skills Marketplace 发现并探索由社区构建的 Agent Skills
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/ar4mirez/samuel --skill echo命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
下载 Zip 下载中... 相关职业
SOC
name echo description Echo framework guardrails, patterns, and best practices for AI-assisted development.
Use when working with Echo projects, or when the user mentions Echo framework.
Provides middleware patterns, routing, context handling, and REST API guidelines.
license MIT metadata {"author":"samuel","version":"1.0","category":"framework","language":"go","extensions":".go"}
Echo Framework Guide
Applies to : Echo v4+, REST APIs, Microservices, High-Performance Web Applications
Language Guide : @.claude/skills/go-guide/SKILL.md
Overview
Echo is a high-performance, extensible, minimalist Go web framework. It features an optimized HTTP router, middleware support, data binding, and rendering.
Use Echo when:
You need high performance with minimal overhead
You want a clean, intuitive API
Built-in middleware matters (JWT, CORS, Gzip, etc.)
You prefer automatic TLS via Let's Encrypt
Consider alternatives when:
You want the most popular framework (use Gin)
You need WebSocket support built-in (use Fiber)
Maximum community resources are needed (use Gin)
Project Structure
myproject/
├── cmd/
│ └── api/
│ └── main.go # Entry point
├── internal/
│ ├── config/
│ │ └── config.go # Configuration
│ ├── handler/
│ │ ├── handler.go # Handler container
│ │ ├── user.go # User handlers
│ │ └── auth.go # Auth handlers
│ ├── middleware/
│ │ ├── auth.go # JWT middleware
│ │ └── custom.go # Custom middleware
│ ├── model/
│ │ ├── user.go # User model
│ │ └── response.go # Response models
│ ├── repository/
│ │ ├── repository.go # Repository interface
│ │ └── user.go # User repository
│ ├── service/
│ │ ├── service.go # Service container
│ │ └── user.go # User service
│ └── validator/
│ └── validator.go # Custom validators
├── pkg/
│ └── response/
│ └── response.go # Response helpers
├── migrations/
├── .env.example
├── go.mod
├── go.sum
├── Makefile
└── README.md
cmd/ for entry points; one main.go per binary
internal/ for private application code; not importable externally
handler/ contains Echo handler functions, thin HTTP layer only
service/ holds business logic; no Echo or HTTP dependencies
repository/ encapsulates data access; accepts context.Context
model/ defines domain structs, request/response DTOs
middleware/ for custom Echo middleware functions
validator/ for custom validation rules via go-playground/validator
Application Setup e := echo.New()
e.HideBanner = true
e.Validator = validator.NewCustomValidator()
e.Use(echoMw.Recover())
e.Use(echoMw.Logger())
e.Use(echoMw.RequestID())
e.Use(echoMw.CORSWithConfig(echoMw.CORSConfig{
AllowOrigins: cfg.CORSOrigins,
AllowMethods: []string {http.MethodGet, http.MethodPost,
http.MethodPut, http.MethodPatch, http.MethodDelete},
AllowHeaders: []string {echo.HeaderOrigin,
echo.HeaderContentType, echo.HeaderAccept,
echo.HeaderAuthorization},
}))
Set e.HideBanner = true in production
Register Recover() first to catch panics in all handlers
Use RequestID() for distributed tracing
Always implement graceful shutdown with e.Shutdown(ctx)
See references/patterns.md for full main.go with graceful shutdown
Routing
Route Groups and Versioning func setupRoutes (e *echo.Echo, h *handler.Handlers, authMw *middleware.AuthMiddleware) {
e.GET("/health" , func (c echo.Context) error {
return c.JSON(http.StatusOK, map [string ]string {"status" : "ok" })
})
v1 := e.Group("/api/v1" )
auth := v1.Group("/auth" )
auth.POST("/login" , h.Auth.Login)
auth.POST("/register" , h.Auth.Register)
auth.POST("/refresh" , h.Auth.Refresh)
users := v1.Group("/users" )
users.POST("" , h.User.Create)
users.Use(authMw.Authenticate)
users.GET("" , h.User.GetAll)
users.GET("/me" , h.User.GetCurrent)
users.GET("/:id" , h.User.GetByID)
users.PUT("/:id" , h.User.Update)
users.DELETE("/:id" , h.User.Delete, authMw.RequireAdmin)
}
Group routes by resource and version (/api/v1/users)
Apply middleware at group level, not per-route when possible
Use /:param for path parameters (e.g., /:id)
Append per-route middleware as extra handler args (e.g., RequireAdmin)
Keep health check outside API groups for monitoring tools
Middleware
Built-in Middleware (use these first) Middleware Purpose Recover()Catch panics, return 500 Logger()Request logging RequestID()Unique request IDs CORS()Cross-origin requests Gzip()Response compression RateLimiter()Rate limiting Secure()Security headers BodyLimit()Request size limits
Custom Middleware Pattern
func RequestTimerMiddleware (next echo.HandlerFunc) echo.HandlerFunc {
return func (c echo.Context) error {
start := time.Now()
err := next(c)
duration := time.Since(start)
c.Response().Header().Set("X-Response-Time" ,
duration.String())
return err
}
}
type RateLimitConfig struct {
Rate int
Burst int
}
func RateLimitMiddleware (cfg RateLimitConfig) echo.MiddlewareFunc {
limiter := rate.NewLimiter(
rate.Limit(cfg.Rate), cfg.Burst,
)
return func (next echo.HandlerFunc) echo.HandlerFunc {
return func (c echo.Context) error {
if !limiter.Allow() {
return c.JSON(http.StatusTooManyRequests,
model.ErrorResponse("rate limit exceeded" ))
}
return next(c)
}
}
}
Return echo.HandlerFunc from middleware
Call next(c) to continue the chain; skip to short-circuit
Configurable middleware returns echo.MiddlewareFunc
Order matters: register Recover() first, then logging, then auth
Echo Context
Reading Values func handler (c echo.Context) error {
id := c.Param("id" )
page := c.QueryParam("page" )
search := c.QueryParam("q" )
name := c.FormValue("name" )
token := c.Request().Header.Get("Authorization" )
userID, ok := c.Get("user_id" ).(uint )
ip := c.RealIP()
ctx := c.Request().Context()
return c.JSON(http.StatusOK, data)
}
Use c.Request().Context() when passing to services/repositories
Use c.Get()/c.Set() for request-scoped values between middleware and handlers
Type-assert values from c.Get() with ok check
Never store echo.Context beyond the request lifecycle
Request Binding and Validation
Binding type CreateUserRequest struct {
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8"`
FirstName string `json:"first_name" validate:"required,min=1,max=100"`
LastName string `json:"last_name" validate:"required,min=1,max=100"`
}
func (h *UserHandler) Create(c echo.Context) error {
var req CreateUserRequest
if err := c.Bind(&req); err != nil {
return c.JSON(http.StatusBadRequest,
model.ErrorResponse(err.Error()))
}
if err := c.Validate(&req); err != nil {
return err
}
}
Custom Validator type CustomValidator struct {
validator *validator.Validate
}
func NewCustomValidator () *CustomValidator {
v := validator.New()
v.RegisterTagNameFunc(func (fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json" ), "," , 2 )[0 ]
if name == "-" {
return ""
}
return name
})
return &CustomValidator{validator: v}
}
func (cv *CustomValidator) Validate(i interface {}) error {
if err := cv.validator.Struct(i); err != nil {
return echo.NewHTTPError(
http.StatusBadRequest,
formatValidationErrors(err),
)
}
return nil
}
Always Bind then Validate as separate steps
Use struct tags: json for binding, validate for rules
Register custom validator on e.Validator at startup
Return structured validation errors, not raw messages
Use pointer fields for optional/partial updates (*string)
Response Patterns Use a consistent JSON envelope across all endpoints:
type Response struct {
Success bool `json:"success"`
Data interface {} `json:"data,omitempty"`
Error string `json:"error,omitempty"`
}
func SuccessResponse (data interface {}) *Response {
return &Response{Success: true , Data: data}
}
func ErrorResponse (msg string ) *Response {
return &Response{Success: false , Error: msg}
}
Use response DTOs; never expose domain models directly (omit passwords, internal IDs)
For paginated responses, include meta with page/total counts
See references/patterns.md for PaginatedResponse struct
Error Handling
Domain Errors var (
ErrUserNotFound = errors.New("user not found" )
ErrUserAlreadyExists = errors.New("user already exists" )
ErrInvalidCredentials = errors.New("invalid credentials" )
)
Handler Error Mapping func (h *UserHandler) GetByID(c echo.Context) error {
id, err := strconv.ParseUint(c.Param("id" ), 10 , 32 )
if err != nil {
return c.JSON(http.StatusBadRequest,
model.ErrorResponse("invalid user ID" ))
}
user, err := h.userService.GetByID(
c.Request().Context(), uint (id),
)
if err != nil {
if errors.Is(err, service.ErrUserNotFound) {
return c.JSON(http.StatusNotFound,
model.ErrorResponse(err.Error()))
}
return c.JSON(http.StatusInternalServerError,
model.ErrorResponse(err.Error()))
}
return c.JSON(http.StatusOK,
model.SuccessResponse(user.ToResponse()))
}
Error handling guidelines:
Define domain errors as sentinel values in the service layer
Map domain errors to HTTP status codes in handlers only
Use errors.Is() / errors.As() for error checking
Never expose internal errors to clients in production
Log detailed errors server-side; return safe messages to clients
Configuration
Load from environment variables (12-factor app) via godotenv
Provide sensible defaults for development only
Never hardcode secrets; use empty defaults to force explicit config
Parse durations and validate at startup, not at use time
See references/patterns.md for full config struct example
Commands Reference
go mod init myproject
go mod tidy
go run cmd/api/main.go
go build -o bin/api cmd/api/main.go
go test ./...
go test -v -cover ./...
go test -race ./...
golangci-lint run
migrate -path migrations -database "$DATABASE_URL " up
migrate -path migrations -database "$DATABASE_URL " down
Dependencies
github.com/labstack/echo/v4
github.com/go -playground/validator/v10
github.com/golang-jwt/jwt/v5
github.com/joho/godotenv
gorm.io/gorm
gorm.io/driver/postgres
golang.org/x/crypto
github.com/stretchr/testify
Best Practices Checklist
Echo-Specific
Use custom validator with go-playground/validator
Use echo.Context for request handling only (not in services)
Use middleware groups for route organization
Return errors from handlers for centralized handling
Use echo.Bind for request binding
Configure proper timeouts and graceful shutdown
Set e.HideBanner = true in production
Performance
Configure database connection pooling (SetMaxOpenConns, etc.)
Implement pagination for list endpoints
Use Gzip() middleware for response compression
Implement request logging middleware for observability
Use BodyLimit() to prevent oversized requests
Advanced Topics For detailed patterns and examples, see:
External References