From golang-orchestrator
Comprehensive guide for the Echo web framework. Use when building scalable, high-performance web applications and REST APIs in Go with features like flexible routing, middleware support, request/response binding, static file serving, and template rendering. Applies to installing Echo, defining routes, implementing middleware, handling requests/responses, and building web services.
npx claudepluginhub linehaul-ai/linehaulai-claude-marketplace --plugin golang-orchestratorThis skill uses the workspace's default tool permissions.
Echo is a high-performance, minimalist Go web framework for building robust REST APIs and web applications with simplicity and efficiency.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides MCP server integration in Claude Code plugins via .mcp.json or plugin.json configs for stdio, SSE, HTTP types, enabling external services as tools.
Echo is a high-performance, minimalist Go web framework for building robust REST APIs and web applications with simplicity and efficiency.
Initialize a Go module and install Echo v4:
mkdir myapp && cd myapp
go mod init myapp
go get github.com/labstack/echo/v4
For Go v1.14 or earlier, enable module mode explicitly:
GO111MODULE=on go get github.com/labstack/echo/v4
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.Logger.Fatal(e.Start(":1323"))
}
Run with go run server.go and visit http://localhost:1323.
Define routes using HTTP methods (GET, POST, PUT, DELETE, PATCH, etc.):
e.POST("/users", saveUser)
e.GET("/users/:id", getUser)
e.PUT("/users/:id", updateUser)
e.DELETE("/users/:id", deleteUser)
Extract dynamic segments from URL paths:
func getUser(c echo.Context) error {
id := c.Param("id")
return c.String(http.StatusOK, id)
}
Access query string parameters:
func show(c echo.Context) error {
team := c.QueryParam("team")
member := c.QueryParam("member")
return c.String(http.StatusOK, "team:" + team + ", member:" + member)
}
Echo supports automatic binding of JSON, XML, form, and query data into Go structs:
type User struct {
Name string `json:"name" xml:"name" form:"name" query:"name"`
Email string `json:"email" xml:"email" form:"email" query:"email"`
}
e.POST("/users", func(c echo.Context) error {
u := new(User)
if err := c.Bind(u); err != nil {
return err
}
return c.JSON(http.StatusCreated, u)
})
Handle application/x-www-form-urlencoded requests:
func save(c echo.Context) error {
name := c.FormValue("name")
email := c.FormValue("email")
return c.String(http.StatusOK, "name:" + name + ", email:" + email)
}
Handle multipart form data with file uploads:
func save(c echo.Context) error {
name := c.FormValue("name")
avatar, err := c.FormFile("avatar")
if err != nil {
return err
}
src, err := avatar.Open()
if err != nil {
return err
}
defer src.Close()
dst, err := os.Create(avatar.Filename)
if err != nil {
return err
}
defer dst.Close()
if _, err = io.Copy(dst, src); err != nil {
return err
}
return c.HTML(http.StatusOK, "<b>Thank you! " + name + "</b>")
}
Send structured data as JSON or XML:
e.GET("/users", func(c echo.Context) error {
u := &User{
Name: "Jon",
Email: "[email protected]",
}
return c.JSON(http.StatusOK, u)
// or
// return c.XML(http.StatusOK, u)
})
Format JSON responses for readability:
return c.JSONPretty(http.StatusOK, u, " ")
Map a URL path to a local directory:
e.Static("/static", "assets")
e.Static("/", "public") // serve from root
Serve individual files:
e.File("/", "public/index.html")
e.File("/favicon.ico", "images/favicon.ico")
Serve Single Page Application assets from embedded Go filesystem:
//go:embed web
var webAssets embed.FS
func main() {
e := echo.New()
e.Use(middleware.StaticWithConfig(middleware.StaticConfig{
HTML5: true,
Root: "web",
Filesystem: http.FS(webAssets),
}))
api := e.Group("/api")
api.GET("/users", func(c echo.Context) error {
return c.String(http.StatusOK, "users")
})
if err := e.Start(":8080"); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatal(err)
}
}
Middleware intercepts requests at root, group, or route levels:
Applied to all routes:
e.Use(middleware.Logger())
e.Use(middleware.Recover())
Applied to specific route groups:
g := e.Group("/admin")
g.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) {
if username == "joe" && password == "secret" {
return true, nil
}
return false, nil
}))
Applied to individual routes:
track := func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
println("request to /users")
return next(c)
}
}
e.GET("/users", func(c echo.Context) error {
return c.String(http.StatusOK, "/users")
}, track)
func main() {
e := echo.New()
// add middleware and routes...
if err := e.Start(":8080"); err != http.ErrServerClosed {
log.Fatal(err)
}
}
if err := e.StartTLS(":8443", "server.crt", "server.key"); err != http.ErrServerClosed {
log.Fatal(err)
}
if err := e.StartTLS(":1323", "cert.pem", "key.pem"); err != http.ErrServerClosed {
log.Fatal(err)
}
s := &http2.Server{
MaxConcurrentStreams: 250,
MaxReadFrameSize: 1048576,
IdleTimeout: 10 * time.Second,
}
if err := e.StartH2CServer(":8080", s); err != http.ErrServerClosed {
log.Fatal(err)
}
For advanced configuration:
s := http.Server{
Addr: ":8080",
Handler: e,
//ReadTimeout: 30 * time.Second,
}
if err := s.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
Use session middleware for maintaining user state:
import "github.com/labstack/echo-contrib/session"
import "github.com/gorilla/sessions"
func main() {
e := echo.New()
e.Use(session.Middleware(sessions.NewCookieStore([]byte("secret"))))
e.GET("/create-session", func(c echo.Context) error {
sess, _ := session.Get("session", c)
sess.Values["foo"] = "bar"
sess.Save(c.Request(), c.Response())
return c.NoContent(http.StatusOK)
})
e.GET("/read-session", func(c echo.Context) error {
sess, _ := session.Get("session", c)
return c.String(http.StatusOK, fmt.Sprintf("foo=%v", sess.Values["foo"]))
})
e.Start(":8080")
}
Integrate distributed tracing with OpenTelemetry SDK and error tracking with Sentry:
import (
"github.com/getsentry/sentry-go"
sentryecho "github.com/getsentry/sentry-go/echo"
"go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
)
func initTracer() (*sdktrace.TracerProvider, error) {
exporter, err := otlptracehttp.New(context.Background(),
otlptracehttp.WithEndpoint("signoz-collector:4318"),
otlptracehttp.WithInsecure(),
)
if err != nil {
return nil, err
}
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName("myapp"),
)),
)
otel.SetTracerProvider(tp)
return tp, nil
}
func main() {
// Initialize Sentry for error tracking
sentry.Init(sentry.ClientOptions{
Dsn: os.Getenv("SENTRY_DSN"),
Environment: os.Getenv("APP_ENV"),
TracesSampleRate: 1.0,
})
defer sentry.Flush(2 * time.Second)
// Initialize OpenTelemetry tracer
tp, _ := initTracer()
defer tp.Shutdown(context.Background())
e := echo.New()
// OpenTelemetry middleware for distributed tracing
e.Use(otelecho.Middleware("myapp"))
// Sentry middleware for error tracking
e.Use(sentryecho.New(sentryecho.Options{Repanic: true}))
e.GET("/hello", func(c echo.Context) error {
return c.String(http.StatusOK, "hello")
})
e.Start(":8080")
}
For structured logging with trace correlation, use zerolog:
import (
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/trace"
)
func LoggerFromContext(ctx context.Context, logger zerolog.Logger) zerolog.Logger {
span := trace.SpanFromContext(ctx)
if span.SpanContext().IsValid() {
return logger.With().
Str("trace_id", span.SpanContext().TraceID().String()).
Str("span_id", span.SpanContext().SpanID().String()).
Logger()
}
return logger
}
Configure structured logging:
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
// Initialize logger (or use global log.Logger)
logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
LogURI: true,
LogStatus: true,
LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
logger.Info().
Str("URI", v.URI).
Int("status", v.Status).
Msg("request")
return nil
},
}))
### Route Export
Export all registered routes as JSON:
```go
routes := e.Routes()
// Each route contains Method, Path, and Name
Context Methods: c.Param(), c.QueryParam(), c.FormValue(), c.FormFile(), c.Bind(), c.String(), c.JSON(), c.XML(), c.HTML(), c.File(), c.Redirect(), c.NoContent()
Echo Methods: e.GET(), e.POST(), e.PUT(), e.DELETE(), e.Static(), e.File(), e.Group(), e.Use(), e.Start(), e.StartTLS(), e.Routes()
echo.Context for request/response manipulation