internal/skills/content/echo/SKILL.md
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.
npx skillsauth add ar4mirez/samuel echoInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Applies to: Echo v4+, REST APIs, Microservices, High-Performance Web Applications Language Guide: @.claude/skills/go-guide/SKILL.md
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:
Consider alternatives when:
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 binaryinternal/ for private application code; not importable externallyhandler/ contains Echo handler functions, thin HTTP layer onlyservice/ holds business logic; no Echo or HTTP dependenciesrepository/ encapsulates data access; accepts context.Contextmodel/ defines domain structs, request/response DTOsmiddleware/ for custom Echo middleware functionsvalidator/ for custom validation rules via go-playground/validatore := echo.New()
e.HideBanner = true
e.Validator = validator.NewCustomValidator()
// Global middleware (order matters)
e.Use(echoMw.Recover()) // First: catch panics
e.Use(echoMw.Logger()) // Second: log all requests
e.Use(echoMw.RequestID()) // Third: trace IDs
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},
}))
Setup guidelines:
e.HideBanner = true in productionRecover() first to catch panics in all handlersRequestID() for distributed tracinge.Shutdown(ctx)main.go with graceful shutdownfunc setupRoutes(e *echo.Echo, h *handler.Handlers, authMw *middleware.AuthMiddleware) {
// Health check (ungrouped)
e.GET("/health", func(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]string{"status": "ok"})
})
// API v1
v1 := e.Group("/api/v1")
// Public routes
auth := v1.Group("/auth")
auth.POST("/login", h.Auth.Login)
auth.POST("/register", h.Auth.Register)
auth.POST("/refresh", h.Auth.Refresh)
// Protected routes
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)
}
Routing guidelines:
/api/v1/users)/:param for path parameters (e.g., /:id)RequireAdmin)| 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 |
// Middleware that injects request-scoped values
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
}
}
// Middleware with configuration
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)
}
}
}
Middleware guidelines:
echo.HandlerFunc from middlewarenext(c) to continue the chain; skip to short-circuitecho.MiddlewareFuncRecover() first, then logging, then authfunc handler(c echo.Context) error {
// Path params
id := c.Param("id")
// Query params
page := c.QueryParam("page")
search := c.QueryParam("q")
// Form values
name := c.FormValue("name")
// Headers
token := c.Request().Header.Get("Authorization")
// Request-scoped values (set by middleware)
userID, ok := c.Get("user_id").(uint)
// Real IP (respects X-Forwarded-For)
ip := c.RealIP()
// Underlying context.Context for DB/service calls
ctx := c.Request().Context()
return c.JSON(http.StatusOK, data)
}
Context guidelines:
c.Request().Context() when passing to services/repositoriesc.Get()/c.Set() for request-scoped values between middleware and handlersc.Get() with ok checkecho.Context beyond the request lifecycletype 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 returns HTTPError
}
// Process valid request...
}
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
}
Binding guidelines:
Bind then Validate as separate stepsjson for binding, validate for rulese.Validator at startup*string)Use a consistent JSON envelope across all endpoints:
// Success: c.JSON(http.StatusOK, SuccessResponse(data))
// Error: c.JSON(http.StatusNotFound, ErrorResponse("not found"))
// Delete: c.NoContent(http.StatusNoContent)
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}
}
meta with page/total countsPaginatedResponse structvar (
ErrUserNotFound = errors.New("user not found")
ErrUserAlreadyExists = errors.New("user already exists")
ErrInvalidCredentials = errors.New("invalid credentials")
)
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:
errors.Is() / errors.As() for error checkinggodotenv# Initialize project
go mod init myproject
# Install dependencies
go mod tidy
# Run development server
go run cmd/api/main.go
# Build binary
go build -o bin/api cmd/api/main.go
# Run tests
go test ./...
go test -v -cover ./...
# Run with race detection
go test -race ./...
# Lint
golangci-lint run
# Database migrations (golang-migrate)
migrate -path migrations -database "$DATABASE_URL" up
migrate -path migrations -database "$DATABASE_URL" down
// Core
github.com/labstack/echo/v4 // Web framework
github.com/go-playground/validator/v10 // Validation
github.com/golang-jwt/jwt/v5 // JWT auth
github.com/joho/godotenv // Env loading
// Database
gorm.io/gorm // ORM
gorm.io/driver/postgres // PostgreSQL driver
// Crypto
golang.org/x/crypto // bcrypt, etc.
// Testing
github.com/stretchr/testify // Assertions and mocks
go-playground/validatorecho.Context for request handling only (not in services)echo.Bind for request bindinge.HideBanner = true in productionSetMaxOpenConns, etc.)Gzip() middleware for response compressionBodyLimit() to prevent oversized requestsFor detailed patterns and examples, see:
development
Zig language guardrails, patterns, and best practices for AI-assisted development. Use when working with Zig files (.zig), build.zig, or when the user mentions Zig. Provides comptime patterns, allocator conventions, C interop guidelines, and testing standards specific to this project's coding standards.
tools
WordPress framework guardrails, patterns, and best practices for AI-assisted development. Use when working with WordPress projects, or when the user mentions WordPress. Provides theme development, plugin architecture, REST API, blocks, and security guidelines.
tools
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs. Use when testing web apps, automating browser interactions, or debugging frontend issues.
tools
Suite of tools for creating elaborate, multi-component web applications using modern frontend technologies (React, Tailwind CSS, shadcn/ui). Use for complex projects requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX pages.