Skip to main content

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:

go
// 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:

go
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:

go
// 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:

go
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:

go
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:

go
// 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:

go
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:

go
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:

go
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:

go
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:

go
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:

go
// 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:

  1. Logger - For request logging and monitoring
  2. Recover - For application stability and panic recovery
  3. CORS - For cross-origin request handling
  4. JWT - For authentication and authorization
  5. Body Limit - For request size restrictions
  6. Gzip - For response compression
  7. 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

  1. 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.

  2. Custom Middleware: Implement a custom middleware that measures and logs the time taken for each request to be processed.

  3. 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.

  4. 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.

  5. 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! :)