You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As of right now, the current middleware API only allows breaking the chain of execution by returning an error. This has many disadvantages, but they all boil down to the caller not having explicit control over the execution of whatever is next. This means that they cannot conditionally return based on the values of the next item in the chain of execution.
Proposal
Inspiration
Package net/http generally uses middlewares like such:
funcmiddleware(next http.Handler) http.Handler {
returnhttp.HandlerFunc(func(w http.ResponseWriter, r*http.Request) {
// Explicit flow control demo.ifr.Header().Get("Action") =="Break me" {
w.Write([]byte("Broken."))
return
}
mockWriter:=newMockWriter(w)
next.ServeHTTP(mockWriter, r)
// Explicit flow control even afterifmockWriter.String() =="Error!" {
w.WriteHeader(500)
}
mockWriter.WriteTo(w)
})
}
This API is good, because although it seems almost too convenient most of the time, there is actually little magic involved in the implementation. It's just a fancy way of wrapping handlers in a chain. go-chi improves this even further by providing a helper router that wraps the chain of middlewares inside a slice:
This proposal asks for an API similar to what net/http has, but with a touch of reflect magic that is internally handled but not exposed. Consider this API:
The bot.Caller interface is added to represent different types of callers. This includes the final function to call as well as other middlewares. The underlying type is purely an implementation detail, thus shouldn't be type-asserted, unless for debugging purposes.
For concreteness, the interface is exactly defined as such:
typeCallerinterface {
// Call is a function that calls the underlying handler. The handler may// return nil values for all, one, the other, or neither.Call(evinterface{}) (*api.SendMessageData, error)
}
Having the interface's underlying type be an implementation detail is very nice, as it allows backwards compatibility with the previous middleware style simply by wrapping a section of the middleware slice inside a struct that implements bot.Caller.
The bot.CallerFunc function is added to wrap the given middleware function around a type that satisfies bot.Caller. It uses reflection to get the event type as well as the return signatures. The possible signatures are:
Similar to before, invalid function signatures will trigger a panic at runtime.
Below are concrete details for other aforementioned types. Note that the middleware function will still only have access to the value of the event, but not what the arguments parsed. This is because the actual argument parsing will be moved to the final call in the chain of execution and into *MethodContext.
package bot
// CallerFunc wraps around functions with the aforementioned possible function// signatures. It panics if an unsupported function is given.funcCallerFunc(vinterface{}) Call// MethodContext is the same old struct with additional type information moved// from the parent subcommand context.typeMethodContextstruct{}
// Call calls the handler method with the given value. It does internal type// checks. If v is a MessageCreateEvent, then the function will parse arguments// from the value by itself. This parser is moved from ctx_call.go.func (c*MethodContext) Call(vinterface{}) (*api.SendMessageData, error)
Breaking changes
This proposal does not include any breaking changes. As mentioned above, the old middleware functions can simply be wrapped inside another type that implements bot.Caller.
The text was updated successfully, but these errors were encountered:
Preamble
As of right now, the current middleware API only allows breaking the chain of execution by returning an error. This has many disadvantages, but they all boil down to the caller not having explicit control over the execution of whatever is next. This means that they cannot conditionally return based on the values of the next item in the chain of execution.
Proposal
Inspiration
Package
net/http
generally uses middlewares like such:This API is good, because although it seems almost too convenient most of the time, there is actually little magic involved in the implementation. It's just a fancy way of wrapping handlers in a chain.
go-chi
improves this even further by providing a helper router that wraps the chain of middlewares inside a slice:New API
This proposal asks for an API similar to what
net/http
has, but with a touch of reflect magic that is internally handled but not exposed. Consider this API:This API adds several new types.
The
bot.Caller
interface is added to represent different types of callers. This includes the final function to call as well as other middlewares. The underlying type is purely an implementation detail, thus shouldn't be type-asserted, unless for debugging purposes.For concreteness, the interface is exactly defined as such:
Having the interface's underlying type be an implementation detail is very nice, as it allows backwards compatibility with the previous middleware style simply by wrapping a section of the middleware slice inside a struct that implements
bot.Caller
.The
bot.CallerFunc
function is added to wrap the given middleware function around a type that satisfiesbot.Caller
. It uses reflection to get the event type as well as the return signatures. The possible signatures are:Similar to before, invalid function signatures will trigger a panic at runtime.
Below are concrete details for other aforementioned types. Note that the middleware function will still only have access to the value of the event, but not what the arguments parsed. This is because the actual argument parsing will be moved to the final call in the chain of execution and into
*MethodContext
.Breaking changes
This proposal does not include any breaking changes. As mentioned above, the old middleware functions can simply be wrapped inside another type that implements
bot.Caller
.The text was updated successfully, but these errors were encountered: