From 4c26dd6e2a6a487a23e73c2a828ec1553834e9ca Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Fri, 3 Oct 2025 03:31:52 -0600 Subject: [PATCH] feat(http/middleware): add idiomatic http-compatible middleware --- http/middleware/middleware.go | 55 +++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 http/middleware/middleware.go diff --git a/http/middleware/middleware.go b/http/middleware/middleware.go new file mode 100644 index 0000000..0c090de --- /dev/null +++ b/http/middleware/middleware.go @@ -0,0 +1,55 @@ +// Copyright 2025 AJ ONeal (https://therootcompany.com) +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. +// +// SPDX-License-Identifier: MPL-2.0 + +package middleware + +import ( + "net/http" + "slices" +) + +// Middleware receives and returns and http.HandlerFunc +type Middleware func(http.HandlerFunc) http.HandlerFunc + +// MiddlewareChain enables inline chaining +type MiddlewareChain struct { + middlewares []Middleware +} + +// New creates a reusable MiddlewareChain with 0 or more middleware +func New(middlewares ...Middleware) MiddlewareChain { + return MiddlewareChain{middlewares: middlewares} +} + +// Use appends additional middleware to the chain +func (c MiddlewareChain) Use(middlewares ...Middleware) MiddlewareChain { + newMiddlewares := make([]Middleware, len(c.middlewares), len(c.middlewares)+len(middlewares)) + copy(newMiddlewares, c.middlewares) + newMiddlewares = append(newMiddlewares, middlewares...) + + return MiddlewareChain{middlewares: newMiddlewares} +} + +// Handle composes middleware with the final handler +func (c MiddlewareChain) Handle(handler http.HandlerFunc) http.HandlerFunc { + if handler == nil { + panic("mw.New(...).Use(...).Handle(-->this<--) requires a handler") + } + + middlewares := make([]Middleware, len(c.middlewares)) + copy(middlewares, c.middlewares) + slices.Reverse(middlewares) + + // Apply middleware in forward order + result := handler + for _, m := range middlewares { + result = m(result) + } + + return result +}