Echo Built-in Middleware
Introduction
Middleware functions are an essential part of web application development, acting as a bridge between the incoming request and the final response. In the Echo framework, middleware provides a way to process HTTP requests and responses before or after your main handler functions execute.
Echo comes with several built-in middleware components that handle common web development tasks like logging, authentication, CORS, request body limiting, and more. These pre-packaged solutions save development time and follow best practices for web application architecture.
In this guide, we'll explore Echo's built-in middleware, understand how they work, and learn how to implement them in your own web applications.
Understanding Echo Middleware Basics
Before diving into specific middleware components, let's understand how middleware works in Echo:
// Basic middleware structure in Echo
func MyMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// Code executed before the request reaches the handler
err := next(c) // Calling the next handler in the chain
// Code executed after the handler is done processing
return err
}
}
Echo middleware can be applied:
- Globally (to all routes)
- To a group of routes
- To specific routes
Common Built-in Middleware Components
1. Logger Middleware
The Logger middleware logs information about each HTTP request including the method, URL, status code, and processing time.
Implementation:
package main
import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
e := echo.New()
// Apply Logger middleware globally
e.Use(middleware.Logger())
e.GET("/", func(c echo.Context) error {
return c.String(200, "Hello, World!")
})
e.Start(":8080")
}
Output Example:
2023/07/15 14:23:15 GET / 200 2.157µs 13B
Customizing the Logger:
// Custom logger configuration
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
Format: "time=${time_rfc3339}, method=${method}, uri=${uri}, status=${status}\n",
}))
2. Recover Middleware
The Recover middleware recovers from panics that might occur during request handling, preventing your entire application from crashing.
Implementation:
package main
import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
e := echo.New()
// Apply Recover middleware globally
e.Use(middleware.Recover())
e.GET("/panic", func(c echo.Context) error {
// This would normally crash your application
panic("Something went wrong!")
})
e.Start(":8080")
}
When accessing /panic
, instead of crashing, the server will recover and return a 500 Internal Server Error response to the client.
3. CORS Middleware
Cross-Origin Resource Sharing (CORS) middleware allows or restricts requested resources from outside domains.
Implementation:
package main
import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
e := echo.New()
// Basic CORS configuration
e.Use(middleware.CORS())
// API endpoints
e.GET("/api/data", func(c echo.Context) error {
return c.JSON(200, map[string]string{"message": "This can be accessed from other domains"})
})
e.Start(":8080")
}
Custom CORS Configuration:
// Advanced CORS configuration
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{"https://yourdomain.com", "https://anotherdomain.com"},
AllowMethods: []string{echo.GET, echo.PUT, echo.POST, echo.DELETE},
AllowHeaders: []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAccept},
AllowCredentials: true,
}))
4. JWT Middleware
JSON Web Token (JWT) middleware provides authentication mechanisms for your API endpoints.
Implementation:
package main
import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
e := echo.New()
// Apply JWT middleware to a group of routes
api := e.Group("/api")
// Configure JWT middleware
api.Use(middleware.JWT([]byte("your-secret-key")))
// Protected route
api.GET("/protected", func(c echo.Context) error {
return c.String(200, "You have accessed a protected route")
})
// Public route
e.GET("/public", func(c echo.Context) error {
return c.String(200, "This is a public route")
})
e.Start(":8080")
}
To access the protected route, a client would need to include a valid JWT in the Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
5. Request Body Limit Middleware
This middleware sets a maximum allowed size for request bodies to prevent potential memory overflow attacks.
Implementation:
package main
import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
e := echo.New()
// Limit request body to 1MB
e.Use(middleware.BodyLimit("1M"))
e.POST("/upload", func(c echo.Context) error {
return c.String(200, "File uploaded successfully")
})
e.Start(":8080")
}
6. Gzip Middleware
The Gzip middleware compresses HTTP responses, reducing bandwidth usage and improving loading times.
Implementation:
package main
import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
e := echo.New()
// Enable Gzip compression
e.Use(middleware.Gzip())
e.GET("/largedata", func(c echo.Context) error {
// Returns a large amount of data that will be compressed
largeText := "..." // Imagine a large string here
return c.String(200, largeText)
})
e.Start(":8080")
}
7. Secure Middleware
The Secure middleware provides various HTTP security headers to protect your application.
Implementation:
package main
import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
e := echo.New()
// Enable security headers
e.Use(middleware.Secure())
e.GET("/", func(c echo.Context) error {
return c.String(200, "This response contains security headers")
})
e.Start(":8080")
}
Added headers include:
- X-XSS-Protection
- X-Content-Type-Options
- X-Frame-Options
- Strict-Transport-Security
- Content-Security-Policy
Real-world Application Example
Let's create a simple REST API with multiple middleware components for a practical example:
package main
import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"net/http"
)
func main() {
// Initialize Echo
e := echo.New()
// Global middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{"*"},
AllowMethods: []string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete},
}))
e.Use(middleware.SecureWithConfig(middleware.SecureConfig{
XSSProtection: "1; mode=block",
ContentTypeNosniff: "nosniff",
XFrameOptions: "SAMEORIGIN",
HSTSMaxAge: 3600,
ContentSecurityPolicy: "default-src 'self'",
}))
// Public routes
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Welcome to the API!")
})
e.POST("/login", handleLogin)
// Private API group with JWT authentication
api := e.Group("/api")
api.Use(middleware.JWTWithConfig(middleware.JWTConfig{
SigningKey: []byte("your-super-secret-key"),
}))
// Secured routes
api.GET("/users", getUsers)
api.POST("/users", createUser)
api.GET("/users/:id", getUser)
api.PUT("/users/:id", updateUser)
api.DELETE("/users/:id", deleteUser)
// Start server
e.Logger.Fatal(e.Start(":8080"))
}
// Handler functions
func handleLogin(c echo.Context) error {
// Authentication logic would go here
// For demonstration purposes, we'll just return a token
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
return c.JSON(http.StatusOK, map[string]string{
"token": token,
})
}
func getUsers(c echo.Context) error {
users := []map[string]interface{}{
{"id": 1, "name": "John Doe"},
{"id": 2, "name": "Jane Smith"},
}
return c.JSON(http.StatusOK, users)
}
func createUser(c echo.Context) error {
// Create user logic
return c.String(http.StatusCreated, "User created")
}
func getUser(c echo.Context) error {
id := c.Param("id")
return c.JSON(http.StatusOK, map[string]interface{}{
"id": id,
"name": "Sample User",
})
}
func updateUser(c echo.Context) error {
id := c.Param("id")
return c.String(http.StatusOK, "User "+id+" updated")
}
func deleteUser(c echo.Context) error {
id := c.Param("id")
return c.String(http.StatusOK, "User "+id+" deleted")
}
This example demonstrates a complete API with:
- Public and protected routes
- Security headers
- CORS configuration
- Request logging
- Panic recovery
- JWT authentication
Combining Multiple Middleware
Echo allows you to chain middleware components to build a robust request/response pipeline:
// Multiple global middleware components
e.Use(middleware.Logger())
e.Use(middleware.Recover())
e.Use(middleware.CORS())
// Or more concisely:
e.Use(
middleware.Logger(),
middleware.Recover(),
middleware.CORS(),
)
// Route-specific middleware
e.GET("/admin", adminHandler, middleware.BasicAuth(validateAdmin))
Summary
Echo's built-in middleware components provide powerful, ready-to-use functionality for common web application needs:
- Logger - For request logging and monitoring
- Recover - For application stability and panic recovery
- CORS - For cross-origin request handling
- JWT - For authentication and authorization
- Body Limit - For request size restrictions
- Gzip - For response compression
- Secure - For security headers
These middleware components can be applied globally, to groups of routes, or to individual routes. By combining multiple middleware, you can create a comprehensive request-processing pipeline that handles everything from logging and security to compression and authentication.
Additional Resources and Exercises
Resources
Exercises
-
Basic Middleware Application: Create a simple Echo server with Logger and Recover middleware. Implement a route that intentionally causes a panic and observe how the Recover middleware handles it.
-
Custom Middleware: Implement a custom middleware that measures and logs the time taken for each request to be processed.
-
Authentication System: Create an API with public and protected routes using JWT middleware. Implement a login endpoint that issues tokens and protected endpoints that verify those tokens.
-
Rate Limiting Middleware: Implement the built-in rate limiting middleware to prevent abuse of your API. Configure it to allow 10 requests per second per IP address.
-
Full API with Multiple Middleware: Build a RESTful API for a blog system with the following middleware: Logger, Recover, CORS, JWT, BodyLimit, and Secure. Create endpoints for posts (CRUD operations) and user authentication.
By experimenting with these exercises, you'll gain practical experience with Echo's middleware system and be able to build robust, secure web applications.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)