Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: net/http: add Middleware interface #60344

Closed
aofei opened this issue May 22, 2023 · 1 comment
Closed

proposal: net/http: add Middleware interface #60344

aofei opened this issue May 22, 2023 · 1 comment

Comments

@aofei
Copy link
Contributor

aofei commented May 22, 2023

Most web developers are familiar with the concept of middleware, which has been adopted in many HTTP routers and web frameworks. This proposal suggests officially introducing the concept of middleware into the net/http package.

Background

Middleware is a design pattern that elegantly allows the addition of cross-cutting concerns such as logging, authentication handling, or recovering from a panic, minimizing the need for multiple code contact points. It acts as a layer between the core application logic and the underlying infrastructure or components. Typically, it intercepts requests or responses and performs certain actions or transformations before passing them along to the next component in the processing pipeline.

In Go, middleware is usually provided by an HTTP router or web framework because the net/http package lacks built-in support for it. However, there are actually functions within the net/http package that essentially act as middlewares. These functions include AllowQuerySemicolons, MaxBytesHandler, StripPrefix, and TimeoutHandler. It's just that they all avoid describing themselves as middlewares. This design choice brings some downsides. For example, it's hard to modify them without breaking compatibility, like we can't add parameters to them. And since their parameters are usually different, we cannot easily form them into a handler chain, but can only call them one by one.

There are already numerous middlewares available in the community. However, most of them are designed specifically for a particular HTTP router or web framework. This is because, without the support of the standard library, it is difficult for people to design a general-purpose middleware without compromising extensibility.

This proposal aims to solve the above problems by officially introducing the middleware design pattern to the net/http package.

Proposal

I propose to add a 1-method interface named "Middleware" to the net/http package. This interface should contain only one method: func(Handler) Handler. The purpose of this method is to chain the Handler passed to it and perform some specific processing before or after the actual execution of the inputted Handler.

Additionally, for ease of use, I propose to add a func(Handler, ...Middleware) Handler to the net/http package. This function is used to associate one or more middlewares with the provided Handler and compose them into a new Handler.

Implementation

This proposal will introduce the following API changes to the net/http package:

package http

// Middleware is used to chain the [Handler].
type Middleware interface {
	// ChainHTTPHandler chains the next to the returned [Handler].
	//
	// Typically, the returned [Handler] is a closure which does something
	// with the [ResponseWriter] and [Request] passed to it, and then calls
	// the next.ServeHTTP.
	ChainHTTPHandler(next Handler) Handler
}

// ApplyMiddleware applies the provided middlewares to the h to form a handler
// chain, and returns a new [Handler] to execute the chain.
//
// For example, ApplyMiddleware(h, m1, m2).ServeHTTP(rw, r) is equivalent to
// m1.ChainHTTPHandler(m2.ChainHTTPHandler(h)).ServeHTTP(rw, r).
func ApplyMiddleware(h Handler, m ...Middleware) Handler { ... }

(Note that the absence of MiddlewareFunc is intentional, giving that #47487 is likely to be accepted. If #47487 is unfortunately rejected, or if this proposal is accepted before #47487, MiddlewareFunc should be added.)

For the implementation of this proposal, the difficult part is naming. For the Middleware interface, some people may use Next(next Handler) Handler as its method. However, in my opinion, "Next" is not an appropriate name, because it says almost nothing. The purpose of the method itself is to return a closure that does something and executes the next handler passed to it. Web developers often describe this behavior as "chaining". And considering the existing ServeHTTP method of the Handler, I think ChainHTTPHandler is a good choice for our Middleware. Alternatively, WithNextHandler could also be a viable option.

@aofei aofei added the Proposal label May 22, 2023
@gopherbot gopherbot added this to the Proposal milestone May 22, 2023
@seankhliao
Copy link
Member

Duplicate of #38479

@seankhliao seankhliao marked this as a duplicate of #38479 May 22, 2023
@seankhliao seankhliao closed this as not planned Won't fix, can't repro, duplicate, stale May 22, 2023
@golang golang locked and limited conversation to collaborators May 21, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants