middleware

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 7, 2026 License: MIT Imports: 8 Imported by: 2

README

go-middleware

A lightweight, standard-compliant HTTP middleware library for Go.

go-middleware provides a set of essential middleware components designed to work seamlessly with the standard net/http package. It avoids custom abstractions, ensuring compatibility with any third-party middleware that follows the standard Go signature.

Features

  • Middleware Chaining: A simple utility to wrap handlers in a sequence of middleware layers.
  • Request Logging:
    • Logs request method, path, response status, duration, and remote address.
    • Automatic X-Request-Id generation and propagation for request tracing.
    • Integration with github.com/meesooqa/go-lgr to provide request-scoped loggers.
  • CORS Support:
    • Configurable allowed origins, methods, and headers.
    • Intelligent handling of AllowCredentials and wildcard origins to comply with browser security specifications.
    • Built-in support for preflight OPTIONS requests.
  • Basic Authentication:
    • Simple protection for administrative routes using ADMIN_USER and ADMIN_PASS environment variables.

Installation

go get github.com/meesooqa/go-middleware

Usage

Middleware Signature and Chaining

The library uses the standard Go middleware pattern: type Middleware func(http.Handler) http.Handler

You can use the Chain function to apply multiple middlewares to a handler. The first middleware in the list is the outermost layer.

package main

import (
	"net/http"
	"github.com/meesooqa/go-middleware"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, World!"))
	})

	// Request flow: Logging -> CORS -> handler
	// Response flow: handler -> CORS -> Logging
	chainedHandler := middleware.Chain(handler, 
		middleware.Logging(nil), 
		middleware.CORS(middleware.CORSConfig{
			AllowedOrigins: []string{"*"},
		}),
	)

	http.ListenAndServe(":8080", chainedHandler)
}
Logging Middleware

The Logging middleware captures the lifecycle of an HTTP request. It integrates with go-lgr to attach a logger containing the request_id to the request context.

// Use slog.Default() if no logger is provided
mw := middleware.Logging(nil) 
CORS Middleware

The CORS middleware handles Cross-Origin Resource Sharing. It is configured via the CORSConfig struct.

corsMw := middleware.CORS(middleware.CORSConfig{
    AllowedOrigins:   []string{"https://example.com", "https://api.example.com"},
    AllowedMethods:   []string{"GET", "POST", "PUT"},
    AllowCredentials: true,
    MaxAge:           12 * time.Hour,
})
Basic Authentication

The BasicAuth middleware protects routes using HTTP Basic Authentication. It is configured via the BasicAuthConfig struct, making it compatible with github.com/meesooqa/go-cfg.

Example of protecting only the /admin section:

mux := http.NewServeMux()

// Public route
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Public Home"))
})

// Protected admin route
adminHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Welcome to the Admin Panel"))
})

// Define authentication config
authCfg := middleware.BasicAuthConfig{
    User:     "admin",
    Password: "secure-password",
}

// Wrap only the admin handler with BasicAuth
mux.Handle("/admin", middleware.BasicAuth(authCfg)(adminHandler))

http.ListenAndServe(":8080", mux)

Configuration

The CORSConfig struct is compatible with github.com/meesooqa/go-cfg, allowing you to load CORS settings directly from a YAML configuration file.

License

This project is licensed under the LICENSE file.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Chain

func Chain(handler http.Handler, mws ...Middleware) http.Handler

Chain wraps the given handler in a middleware chain. The first element in the list is the outermost middleware: it receives the request first and sees the response last.

Chain(handler, A, B) is equivalent to A(B(handler))
→ request flow: A → B → handler
→ response flow: handler → B → A

Types

type BasicAuthConfig added in v0.2.0

type BasicAuthConfig struct {
	// User is the username required for authentication.
	User string `env:"ADMIN_USER"`

	// Password is the password required for authentication.
	Password string `env:"ADMIN_PASS"`
}

BasicAuthConfig defines the configuration for the BasicAuth middleware.

Struct tags are compatible with `github.com/meesooqa/go-cfg`

type CORSConfig

type CORSConfig struct {
	// AllowedOrigins is a list of permitted origins, or ["*"] to allow all.
	// Empty by default (CORS is disabled)
	AllowedOrigins []string `yaml:"allowed_origins"`

	// AllowedMethods is a list of HTTP methods permitted in the preflight response
	AllowedMethods []string `yaml:"allowed_methods" default:"GET,POST,PUT,PATCH,DELETE,OPTIONS"`

	// AllowedHeaders is a list of headers permitted in the preflight response
	AllowedHeaders []string `yaml:"allowed_headers" default:"Content-Type,Authorization"`

	// AllowCredentials allows sending credentials (cookies, Authorization)
	// in cross-origin requests. See the warning in CORS() —
	// this is incompatible with AllowedOrigins: ["*"] per the specification
	AllowCredentials bool `yaml:"allow_credentials" default:"false"`

	// MaxAge specifies how long the browser can cache the preflight request response
	MaxAge time.Duration `yaml:"max_age" default:"12h"`
}

CORSConfig defines the configuration for the CORS middleware. By default, AllowedOrigins is empty, meaning no CORS headers are added (a safe default: the browser applies the standard same-origin policy). To enable cross-origin requests, explicitly set AllowedOrigins

Struct tags are compatible with `github.com/meesooqa/go-cfg`

type Middleware

type Middleware func(http.Handler) http.Handler

Middleware is a function that wraps one http.Handler with another. It uses the standard Go signature, directly compatible with net/http without any custom abstraction layers, any existing third-party middleware following this pattern can be used seamlessly without adapters

func BasicAuth added in v0.2.0

func BasicAuth(cfg BasicAuthConfig) Middleware

BasicAuth is a middleware that protects routes using HTTP Basic Authentication. It verifies the request credentials against the provided configuration. If authentication fails, it returns a 401 Unauthorized response with the WWW-Authenticate header, prompting the browser for credentials.

func CORS

func CORS(c CORSConfig) Middleware

CORS creates a middleware that adds CORS headers based on c. If c.AllowedOrigins is empty, the middleware is a no-op; it simply passes the request through without adding any headers.

An important nuance of the CORS specification: the combination of AllowedOrigins: ["*"] and AllowCredentials: true is prohibited by browsers; a server must not return Access-Control-Allow-Origin: * alongside Access-Control-Allow-Credentials: true. In this case, the middleware automatically falls back to "echoing" the specific request origin instead of using "*", ensuring the configuration remains functional rather than being silently rejected by the browser.

func Logging

func Logging(logger *slog.Logger) Middleware

Logging creates a middleware that logs every request: method, path, response status, duration, and client address. If logger is nil, slog.Default() is used.

Additionally, the middleware attaches a request-scoped logger (enriched with a request_id) to the request's context.Context via lgr.NewContext. Controller handlers can retrieve it using lgr.FromContext(r.Context()), ensuring all their log entries are automatically tagged with the same request_id as the final "request completed" entry.

The request_id is extracted from the X-Request-Id header if provided by the client or proxy; otherwise, a random one is generated. In either case, it is returned in the X-Request-Id response header.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL