echo

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: echo for comprehensive documentation.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "echo" with this command: npx skills add claude-dev-suite/claude-dev-suite/claude-dev-suite-claude-dev-suite-echo

Echo Core Knowledge

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: echo for comprehensive documentation.

Basic Setup

package main

import ( "github.com/labstack/echo/v4" "net/http" )

func main() { e := echo.New()

e.GET("/", func(c echo.Context) error {
    return c.String(http.StatusOK, "Hello, World!")
})

e.Logger.Fatal(e.Start(":8080"))

}

Routing

Basic Routes

e := echo.New()

e.GET("/users", listUsers) e.GET("/users/:id", getUser) e.POST("/users", createUser) e.PUT("/users/:id", updateUser) e.DELETE("/users/:id", deleteUser)

// Any method e.Any("/any", handleAny)

// Match specific methods e.Match([]string{"GET", "POST"}, "/multi", handler)

Path Parameters

// Single parameter e.GET("/users/:id", func(c echo.Context) error { id := c.Param("id") return c.JSON(http.StatusOK, map[string]string{"id": id}) })

// Multiple parameters e.GET("/users/:userId/posts/:postId", func(c echo.Context) error { userId := c.Param("userId") postId := c.Param("postId") return c.JSON(http.StatusOK, map[string]string{ "userId": userId, "postId": postId, }) })

Route Groups

api := e.Group("/api")

v1 := api.Group("/v1") v1.GET("/users", listUsersV1) v1.POST("/users", createUserV1)

v2 := api.Group("/v2") v2.GET("/users", listUsersV2) v2.POST("/users", createUserV2)

// Group with middleware admin := api.Group("/admin", adminMiddleware) admin.GET("/stats", getStats)

Context

Request Data

func handler(c echo.Context) error { // Path params id := c.Param("id")

// Query params
page := c.QueryParam("page")
pageInt, _ := strconv.Atoi(c.QueryParam("page"))

// Form data
name := c.FormValue("name")

// Headers
auth := c.Request().Header.Get("Authorization")

// Cookies
cookie, _ := c.Cookie("session")

return c.NoContent(http.StatusOK)

}

Binding

type CreateUserRequest struct { Name string json:"name" validate:"required" Email string json:"email" validate:"required,email" }

func createUser(c echo.Context) error { var req CreateUserRequest if err := c.Bind(&req); err != nil { return echo.NewHTTPError(http.StatusBadRequest, err.Error()) }

return c.JSON(http.StatusCreated, req)

}

// Query binding type ListQuery struct { Page int query:"page" PerPage int query:"per_page" }

func listUsers(c echo.Context) error { var query ListQuery if err := c.Bind(&query); err != nil { return err } return c.JSON(http.StatusOK, query) }

Validation

import "github.com/go-playground/validator/v10"

type CustomValidator struct { validator *validator.Validate }

func (cv *CustomValidator) Validate(i interface{}) error { if err := cv.validator.Struct(i); err != nil { return echo.NewHTTPError(http.StatusBadRequest, err.Error()) } return nil }

func main() { e := echo.New() e.Validator = &CustomValidator{validator: validator.New()}

e.POST("/users", createUser)
e.Logger.Fatal(e.Start(":8080"))

}

func createUser(c echo.Context) error { var req CreateUserRequest if err := c.Bind(&req); err != nil { return err } if err := c.Validate(req); err != nil { return err } return c.JSON(http.StatusCreated, req) }

Middleware

Built-in Middleware

import ( "github.com/labstack/echo/v4/middleware" )

e := echo.New()

e.Use(middleware.Logger()) e.Use(middleware.Recover()) e.Use(middleware.RequestID()) e.Use(middleware.Gzip())

// CORS e.Use(middleware.CORSWithConfig(middleware.CORSConfig{ AllowOrigins: []string{"https://example.com"}, AllowMethods: []string{echo.GET, echo.POST, echo.PUT, echo.DELETE}, AllowHeaders: []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAuthorization}, }))

// Rate limiter e.Use(middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(20)))

Custom Middleware

func TimingMiddleware(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 } }

e.Use(TimingMiddleware)

Authentication Middleware

func AuthMiddleware(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { auth := c.Request().Header.Get("Authorization")

    if auth == "" {
        return echo.NewHTTPError(http.StatusUnauthorized, "missing token")
    }

    if !strings.HasPrefix(auth, "Bearer ") {
        return echo.NewHTTPError(http.StatusUnauthorized, "invalid format")
    }

    token := auth[7:]
    user, err := validateToken(token)
    if err != nil {
        return echo.NewHTTPError(http.StatusUnauthorized, "invalid token")
    }

    c.Set("user", user)
    return next(c)
}

}

protected := e.Group("/api", AuthMiddleware) protected.GET("/me", getMe)

func getMe(c echo.Context) error { user := c.Get("user").(*User) return c.JSON(http.StatusOK, user) }

JWT Middleware

import "github.com/labstack/echo-jwt/v4"

e.Use(echojwt.WithConfig(echojwt.Config{ SigningKey: []byte("secret"), NewClaimsFunc: func(c echo.Context) jwt.Claims { return new(jwtCustomClaims) }, }))

Response

Response Types

// JSON c.JSON(http.StatusOK, map[string]string{"message": "hello"})

// String c.String(http.StatusOK, "Hello, World!")

// HTML c.HTML(http.StatusOK, "<h1>Hello</h1>")

// XML c.XML(http.StatusOK, data)

// Blob c.Blob(http.StatusOK, "application/octet-stream", bytes)

// File c.File("./static/file.txt")

// Redirect c.Redirect(http.StatusMovedPermanently, "https://example.com")

// No Content c.NoContent(http.StatusNoContent)

WebSocket

import ( "github.com/gorilla/websocket" )

var upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, }

e.GET("/ws", func(c echo.Context) error { ws, err := upgrader.Upgrade(c.Response(), c.Request(), nil) if err != nil { return err } defer ws.Close()

for {
    mt, msg, err := ws.ReadMessage()
    if err != nil {
        break
    }

    if err := ws.WriteMessage(mt, msg); err != nil {
        break
    }
}
return nil

})

Error Handling

HTTP Errors

func getUser(c echo.Context) error { id := c.Param("id") user, err := findUser(id) if err != nil { return echo.NewHTTPError(http.StatusNotFound, "user not found") } return c.JSON(http.StatusOK, user) }

Custom Error Handler

func customHTTPErrorHandler(err error, c echo.Context) { code := http.StatusInternalServerError message := "Internal Server Error"

if he, ok := err.(*echo.HTTPError); ok {
    code = he.Code
    message = he.Message.(string)
}

c.Logger().Error(err)
c.JSON(code, map[string]interface{}{
    "error":   http.StatusText(code),
    "message": message,
})

}

e.HTTPErrorHandler = customHTTPErrorHandler

Production Readiness

Health Checks

e.GET("/health", func(c echo.Context) error { return c.JSON(http.StatusOK, map[string]string{"status": "healthy"}) })

e.GET("/ready", func(c echo.Context) error { ctx, cancel := context.WithTimeout(c.Request().Context(), 2*time.Second) defer cancel()

if err := db.PingContext(ctx); err != nil {
    return c.JSON(http.StatusServiceUnavailable, map[string]string{
        "status":   "not ready",
        "database": "disconnected",
    })
}

return c.JSON(http.StatusOK, map[string]string{
    "status":   "ready",
    "database": "connected",
})

})

Graceful Shutdown

func main() { e := echo.New() e.GET("/", handler)

go func() {
    if err := e.Start(":8080"); err != http.ErrServerClosed {
        e.Logger.Fatal("shutting down the server")
    }
}()

quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
&#x3C;-quit

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

if err := e.Shutdown(ctx); err != nil {
    e.Logger.Fatal(err)
}

}

Checklist

  • Recovery middleware enabled

  • CORS configured

  • Rate limiting enabled

  • Request validation

  • Custom error handler

  • Health/readiness endpoints

  • Graceful shutdown

  • Structured logging

When NOT to Use This Skill

  • Gin projects - Gin has different context and binding API

  • Fiber projects - Fiber is Express-like with different patterns

  • Chi projects - Chi is more stdlib-compatible

  • Simple stdlib servers - Echo adds framework overhead

  • gRPC-only services - Use gRPC framework directly

Anti-Patterns

Anti-Pattern Why It's Bad Solution

Not returning from middleware Handler executes anyway Return early on auth failures

Using c.JSON() without status Unclear response codes Always specify status code first

Missing error handling Panics in production Use echo.NewHTTPError()

Global validator not set No validation Set e.Validator with custom validator

Not using groups Flat route structure Group routes with e.Group()

Ignoring context cancellation Long-running requests Check c.Request().Context()

Quick Troubleshooting

Problem Diagnosis Fix

Middleware not executing Wrong position Place before route registration

Validation not working No validator set Set e.Validator with go-playground/validator

CORS errors Not configured Use middleware.CORS()

Route not matching Parameter mismatch Check path parameter syntax :id

WebSocket handshake fails Wrong upgrade header Use gorilla/websocket upgrader

Panic on nil pointer Missing error check Check c.Bind() return value

Reference Documentation

  • Routing

  • Context

  • Middleware

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

Alexa CLI

Control Amazon Alexa devices and smart home via the `alexacli` CLI. Use when a user asks to speak/announce on Echo devices, control lights/thermostats/locks, send voice commands, or query Alexa.

Registry SourceRecently Updated
143.3K
Profile unavailable
Coding

cron-scheduling

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

token-optimization

No summary provided by upstream source.

Repository SourceNeeds Review