echo
Echo Web Framework
Echo is a high-performance, minimalist Go web framework for building robust REST APIs and web applications with simplicity and efficiency.
Installation
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
Quick Start
Hello World Server
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.
Routing
Basic Routes
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)
Path Parameters
Extract dynamic segments from URL paths:
func getUser(c echo.Context) error {
id := c.Param("id")
return c.String(http.StatusOK, id)
}
Query Parameters
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)
}
Request Handling
Bind Request Data
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)
})
Form Data
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)
}
File Uploads
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>")
}
Response Handling
JSON and XML Responses
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)
})
Pretty-Printed JSON
Format JSON responses for readability:
return c.JSONPretty(http.StatusOK, u, " ")
Static Files
Serve Directory
Map a URL path to a local directory:
e.Static("/static", "assets")
e.Static("/", "public") // serve from root
Serve Single File
Serve individual files:
e.File("/", "public/index.html")
e.File("/favicon.ico", "images/favicon.ico")
Embedded Filesystem (SPA)
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
Middleware intercepts requests at root, group, or route levels:
Root-Level Middleware
Applied to all routes:
e.Use(middleware.Logger())
e.Use(middleware.Recover())
Group-Level Middleware
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
}))
Route-Level Middleware
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)
Server Startup
HTTP Server
func main() {
e := echo.New()
// add middleware and routes...
if err := e.Start(":8080"); err != http.ErrServerClosed {
log.Fatal(err)
}
}
HTTPS/TLS Server
if err := e.StartTLS(":8443", "server.crt", "server.key"); err != http.ErrServerClosed {
log.Fatal(err)
}
HTTP/2 Server
if err := e.StartTLS(":1323", "cert.pem", "key.pem"); err != http.ErrServerClosed {
log.Fatal(err)
}
HTTP/2 Cleartext (H2C)
s := &http2.Server{
MaxConcurrentStreams: 250,
MaxReadFrameSize: 1048576,
IdleTimeout: 10 * time.Second,
}
if err := e.StartH2CServer(":8080", s); err != http.ErrServerClosed {
log.Fatal(err)
}
Custom HTTP Server
For advanced configuration:
s := http.Server{
Addr: ":8080",
Handler: e,
//ReadTimeout: 30 * time.Second,
}
if err := s.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
Advanced Features
Session Management
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")
}
Observability (OpenTelemetry + Sentry)
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
}
Request Logger with ZeroLog
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
Key Echo Methods
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()
Best Practices
- Use middleware for cross-cutting concerns (logging, auth, CORS)
- Bind request data to typed structs for safety
- Return appropriate HTTP status codes
- Group related routes for shared middleware
- Use
echo.Contextfor request/response manipulation - Handle errors explicitly and return meaningful responses
- Leverage middleware ecosystem for common features (JWT, CORS, compression, etc.)
More from linehaul-ai/linehaulai-claude-marketplace
geospatial-postgis-patterns
Implement geofences, spatial queries, real-time tracking, and mapping features in laneweaverTMS using PostGIS and PGRouting. Use when building location-based features, distance calculations, ETA predictions, or fleet visualization.
83quickbooks-online-api
Expert guide for QuickBooks Online API integration covering authentication, CRUD operations, batch processing, and best practices for invoicing, payments, and customer management.
61rbac-authorization-patterns
Provide patterns for implementing Role-Based Access Control and multi-tenant authorization in laneweaverTMS. Use when implementing user roles, permissions, tenant isolation, Echo authorization middleware, RLS policies for multi-tenant access, or JWT claims structure for freight brokerage applications.
61slack-block-kit
Build Slack Block Kit UIs for messages, modals, and Home tabs. Use when creating Slack notifications, interactive forms, bot responses, app dashboards, or any Slack UI. Covers blocks (Section, Actions, Input, Header), elements (Buttons, Selects, Date pickers), composition objects, and the slack-block-builder library.
44svelte-flow
Build node-based editors, interactive diagrams, and flow visualizations using Svelte Flow. Use when creating workflow editors, data flow diagrams, organizational charts, mindmaps, process visualizations, DAG editors, or any interactive node-graph UI. Supports custom nodes/edges, layouts (dagre, hierarchical), animations, and advanced features like proximity connect, floating edges, and contextual zoom.
35testcontainers-go
Use this skill when writing Go integration tests with Docker containers, using testcontainers-go modules (postgres, redis, kafka, etc.), setting up container-based test infrastructure, or configuring container networking and wait strategies. Covers 62+ pre-configured modules, cleanup patterns, and multi-container setups.
34