mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01:00
New 'Application.UseRouter(...Handler)'. Read HISTORY.md
This commit is contained in:
parent
24de7bf7fb
commit
da029d6f37
|
@ -359,6 +359,8 @@ Response:
|
||||||
|
|
||||||
Other Improvements:
|
Other Improvements:
|
||||||
|
|
||||||
|
- `Application.UseRouter(...Handler)` - to register handlers before the main router, useful on handlers that should control whether the router itself should ran or not. Independently of the incoming request's method and path values. These handlers will be executed ALWAYS against ALL incoming requests. Example of use-case: CORS.
|
||||||
|
|
||||||
- `*versioning.Group` type is a full `Party` now.
|
- `*versioning.Group` type is a full `Party` now.
|
||||||
|
|
||||||
- `Party.UseOnce` - either inserts a middleware, or on the basis of the middleware already existing, replace that existing middleware instead.
|
- `Party.UseOnce` - either inserts a middleware, or on the basis of the middleware already existing, replace that existing middleware instead.
|
||||||
|
|
|
@ -18,7 +18,8 @@ import (
|
||||||
// User can refresh the router with `RefreshRouter` whenever a route's field is changed by him.
|
// User can refresh the router with `RefreshRouter` whenever a route's field is changed by him.
|
||||||
type Router struct {
|
type Router struct {
|
||||||
mu sync.Mutex // for Downgrade, WrapRouter & BuildRouter,
|
mu sync.Mutex // for Downgrade, WrapRouter & BuildRouter,
|
||||||
// not indeed but we don't to risk its usage by third-parties.
|
|
||||||
|
preHandlers context.Handlers // run before requestHandler, as middleware, same way context's handlers run, see `UseRouter`.
|
||||||
requestHandler RequestHandler // build-accessible, can be changed to define a custom router or proxy, used on RefreshRouter too.
|
requestHandler RequestHandler // build-accessible, can be changed to define a custom router or proxy, used on RefreshRouter too.
|
||||||
mainHandler http.HandlerFunc // init-accessible
|
mainHandler http.HandlerFunc // init-accessible
|
||||||
wrapperFunc WrapperFunc
|
wrapperFunc WrapperFunc
|
||||||
|
@ -86,6 +87,25 @@ func (router *Router) FindClosestPaths(subdomain, searchPath string, n int) []st
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UseRouter registers one or more handlers that are fired
|
||||||
|
// before the main router's request handler.
|
||||||
|
//
|
||||||
|
// Use this method to register handlers, that can ran
|
||||||
|
// independently of the incoming request's method and path values,
|
||||||
|
// that they will be executed ALWAYS against ALL incoming requests.
|
||||||
|
// Example of use-case: CORS.
|
||||||
|
//
|
||||||
|
// Note that because these are executed before the router itself
|
||||||
|
// the Context should not have access to the `GetCurrentRoute`
|
||||||
|
// as it is not decided yet which route is responsible to handle the incoming request.
|
||||||
|
// It's one level higher than the `WrapRouter`.
|
||||||
|
// The context SHOULD call its `Next` method in order to proceed to
|
||||||
|
// the next handler in the chain or the main request handler one.
|
||||||
|
// ExecutionRules are NOT applied here.
|
||||||
|
func (router *Router) UseRouter(handlers ...context.Handler) {
|
||||||
|
router.preHandlers = append(router.preHandlers, handlers...)
|
||||||
|
}
|
||||||
|
|
||||||
// BuildRouter builds the router based on
|
// BuildRouter builds the router based on
|
||||||
// the context factory (explicit pool in this case),
|
// the context factory (explicit pool in this case),
|
||||||
// the request handler which manages how the main handler will multiplexes the routes
|
// the request handler which manages how the main handler will multiplexes the routes
|
||||||
|
@ -130,12 +150,27 @@ func (router *Router) BuildRouter(cPool *context.Pool, requestHandler RequestHan
|
||||||
}
|
}
|
||||||
|
|
||||||
// the important
|
// the important
|
||||||
router.mainHandler = func(w http.ResponseWriter, r *http.Request) {
|
if len(router.preHandlers) > 0 {
|
||||||
ctx := cPool.Acquire(w, r)
|
handlers := append(router.preHandlers, func(ctx *context.Context) {
|
||||||
// Note: we can't get all r.Context().Value key-value pairs
|
// set the handler index back to 0 so the route's handlers can be executed as exepcted.
|
||||||
// and save them to ctx.values.
|
ctx.HandlerIndex(0)
|
||||||
router.requestHandler.HandleRequest(ctx)
|
// execute the main request handler, this will fire the found route's handlers
|
||||||
cPool.Release(ctx)
|
// or if error the error code's associated handler.
|
||||||
|
router.requestHandler.HandleRequest(ctx)
|
||||||
|
})
|
||||||
|
|
||||||
|
router.mainHandler = func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := cPool.Acquire(w, r)
|
||||||
|
// execute the final handlers chain.
|
||||||
|
ctx.Do(handlers)
|
||||||
|
cPool.Release(ctx)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
router.mainHandler = func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := cPool.Acquire(w, r)
|
||||||
|
router.requestHandler.HandleRequest(ctx)
|
||||||
|
cPool.Release(ctx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if router.wrapperFunc != nil { // if wrapper used then attach that as the router service
|
if router.wrapperFunc != nil { // if wrapper used then attach that as the router service
|
||||||
|
|
|
@ -7,11 +7,10 @@
|
||||||
package router_test
|
package router_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/kataras/iris/v12"
|
"github.com/kataras/iris/v12"
|
||||||
"github.com/kataras/iris/v12/context"
|
|
||||||
|
|
||||||
"github.com/kataras/iris/v12/httptest"
|
"github.com/kataras/iris/v12/httptest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,48 +18,43 @@ import (
|
||||||
// with a different order but the route's final
|
// with a different order but the route's final
|
||||||
// response should be the same at all cases.
|
// response should be the same at all cases.
|
||||||
var (
|
var (
|
||||||
mainResponse = "main"
|
writeHandler = func(s string) iris.Handler {
|
||||||
mainHandler = func(ctx *context.Context) {
|
return func(ctx iris.Context) {
|
||||||
ctx.WriteString(mainResponse)
|
ctx.WriteString(s)
|
||||||
ctx.Next()
|
ctx.Next()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mainResponse = "main"
|
||||||
|
mainHandler = writeHandler(mainResponse)
|
||||||
|
|
||||||
firstUseResponse = "use1"
|
firstUseResponse = "use1"
|
||||||
firstUseHandler = func(ctx *context.Context) {
|
firstUseHandler = writeHandler(firstUseResponse)
|
||||||
ctx.WriteString(firstUseResponse)
|
|
||||||
ctx.Next()
|
|
||||||
}
|
|
||||||
|
|
||||||
secondUseResponse = "use2"
|
secondUseResponse = "use2"
|
||||||
secondUseHandler = func(ctx *context.Context) {
|
secondUseHandler = writeHandler(secondUseResponse)
|
||||||
ctx.WriteString(secondUseResponse)
|
|
||||||
ctx.Next()
|
firstUseRouterResponse = "userouter1"
|
||||||
}
|
firstUseRouterHandler = writeHandler(firstUseRouterResponse)
|
||||||
|
|
||||||
|
secondUseRouterResponse = "userouter2"
|
||||||
|
secondUseRouterHandler = writeHandler(secondUseRouterResponse)
|
||||||
|
|
||||||
firstUseGlobalResponse = "useglobal1"
|
firstUseGlobalResponse = "useglobal1"
|
||||||
firstUseGlobalHandler = func(ctx *context.Context) {
|
firstUseGlobalHandler = writeHandler(firstUseGlobalResponse)
|
||||||
ctx.WriteString(firstUseGlobalResponse)
|
|
||||||
ctx.Next()
|
|
||||||
}
|
|
||||||
|
|
||||||
secondUseGlobalResponse = "useglobal2"
|
secondUseGlobalResponse = "useglobal2"
|
||||||
secondUseGlobalHandler = func(ctx *context.Context) {
|
secondUseGlobalHandler = writeHandler(secondUseGlobalResponse)
|
||||||
ctx.WriteString(secondUseGlobalResponse)
|
|
||||||
ctx.Next()
|
|
||||||
}
|
|
||||||
|
|
||||||
firstDoneResponse = "done1"
|
firstDoneResponse = "done1"
|
||||||
firstDoneHandler = func(ctx *context.Context) {
|
firstDoneHandler = writeHandler(firstDoneResponse)
|
||||||
ctx.WriteString(firstDoneResponse)
|
|
||||||
ctx.Next()
|
|
||||||
}
|
|
||||||
|
|
||||||
secondDoneResponse = "done2"
|
secondDoneResponse = "done2"
|
||||||
secondDoneHandler = func(ctx *context.Context) {
|
secondDoneHandler = func(ctx iris.Context) {
|
||||||
ctx.WriteString(secondDoneResponse)
|
ctx.WriteString(secondDoneResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
finalResponse = firstUseGlobalResponse + secondUseGlobalResponse +
|
finalResponse = firstUseRouterResponse + secondUseRouterResponse + firstUseGlobalResponse + secondUseGlobalResponse +
|
||||||
firstUseResponse + secondUseResponse + mainResponse + firstDoneResponse + secondDoneResponse
|
firstUseResponse + secondUseResponse + mainResponse + firstDoneResponse + secondDoneResponse
|
||||||
|
|
||||||
testResponse = func(t *testing.T, app *iris.Application, path string) {
|
testResponse = func(t *testing.T, app *iris.Application, path string) {
|
||||||
|
@ -73,6 +67,9 @@ var (
|
||||||
|
|
||||||
func TestMiddlewareByRouteDef(t *testing.T) {
|
func TestMiddlewareByRouteDef(t *testing.T) {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
app.UseRouter(firstUseRouterHandler)
|
||||||
|
app.UseRouter(secondUseRouterHandler)
|
||||||
|
|
||||||
app.Get("/mypath", firstUseGlobalHandler, secondUseGlobalHandler, firstUseHandler, secondUseHandler,
|
app.Get("/mypath", firstUseGlobalHandler, secondUseGlobalHandler, firstUseHandler, secondUseHandler,
|
||||||
mainHandler, firstDoneHandler, secondDoneHandler)
|
mainHandler, firstDoneHandler, secondDoneHandler)
|
||||||
|
|
||||||
|
@ -81,6 +78,7 @@ func TestMiddlewareByRouteDef(t *testing.T) {
|
||||||
|
|
||||||
func TestMiddlewareByUseAndDoneDef(t *testing.T) {
|
func TestMiddlewareByUseAndDoneDef(t *testing.T) {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
app.UseRouter(firstUseRouterHandler, secondUseRouterHandler)
|
||||||
app.Use(firstUseGlobalHandler, secondUseGlobalHandler, firstUseHandler, secondUseHandler)
|
app.Use(firstUseGlobalHandler, secondUseGlobalHandler, firstUseHandler, secondUseHandler)
|
||||||
app.Done(firstDoneHandler, secondDoneHandler)
|
app.Done(firstDoneHandler, secondDoneHandler)
|
||||||
|
|
||||||
|
@ -91,12 +89,14 @@ func TestMiddlewareByUseAndDoneDef(t *testing.T) {
|
||||||
|
|
||||||
func TestMiddlewareByUseUseGlobalAndDoneDef(t *testing.T) {
|
func TestMiddlewareByUseUseGlobalAndDoneDef(t *testing.T) {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
|
||||||
app.Use(firstUseHandler, secondUseHandler)
|
app.Use(firstUseHandler, secondUseHandler)
|
||||||
// if failed then UseGlobal didnt' registered these handlers even before the
|
// if failed then UseGlobal didnt' registered these handlers even before the
|
||||||
// existing middleware.
|
// existing middleware.
|
||||||
app.UseGlobal(firstUseGlobalHandler, secondUseGlobalHandler)
|
app.UseGlobal(firstUseGlobalHandler, secondUseGlobalHandler)
|
||||||
app.Done(firstDoneHandler, secondDoneHandler)
|
app.Done(firstDoneHandler, secondDoneHandler)
|
||||||
|
|
||||||
|
app.UseRouter(firstUseRouterHandler, secondUseRouterHandler)
|
||||||
app.Get("/mypath", mainHandler)
|
app.Get("/mypath", mainHandler)
|
||||||
|
|
||||||
testResponse(t, app, "/mypath")
|
testResponse(t, app, "/mypath")
|
||||||
|
@ -104,6 +104,7 @@ func TestMiddlewareByUseUseGlobalAndDoneDef(t *testing.T) {
|
||||||
|
|
||||||
func TestMiddlewareByUseDoneAndUseGlobalDef(t *testing.T) {
|
func TestMiddlewareByUseDoneAndUseGlobalDef(t *testing.T) {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
app.UseRouter(firstUseRouterHandler, secondUseRouterHandler)
|
||||||
|
|
||||||
app.Use(firstUseHandler, secondUseHandler)
|
app.Use(firstUseHandler, secondUseHandler)
|
||||||
app.Done(firstDoneHandler, secondDoneHandler)
|
app.Done(firstDoneHandler, secondDoneHandler)
|
||||||
|
@ -123,6 +124,8 @@ func TestMiddlewareByUseDoneAndUseGlobalDef(t *testing.T) {
|
||||||
|
|
||||||
func TestMiddlewareByUseGlobalUseAndDoneGlobalDef(t *testing.T) {
|
func TestMiddlewareByUseGlobalUseAndDoneGlobalDef(t *testing.T) {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
app.UseRouter(firstUseRouterHandler)
|
||||||
|
app.UseRouter(secondUseRouterHandler)
|
||||||
|
|
||||||
app.UseGlobal(firstUseGlobalHandler)
|
app.UseGlobal(firstUseGlobalHandler)
|
||||||
app.UseGlobal(secondUseGlobalHandler)
|
app.UseGlobal(secondUseGlobalHandler)
|
||||||
|
@ -137,6 +140,7 @@ func TestMiddlewareByUseGlobalUseAndDoneGlobalDef(t *testing.T) {
|
||||||
|
|
||||||
func TestMiddlewareByDoneUseAndUseGlobalDef(t *testing.T) {
|
func TestMiddlewareByDoneUseAndUseGlobalDef(t *testing.T) {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
app.UseRouter(firstUseRouterHandler, secondUseRouterHandler)
|
||||||
app.Done(firstDoneHandler, secondDoneHandler)
|
app.Done(firstDoneHandler, secondDoneHandler)
|
||||||
|
|
||||||
app.Use(firstUseHandler, secondUseHandler)
|
app.Use(firstUseHandler, secondUseHandler)
|
||||||
|
@ -148,3 +152,29 @@ func TestMiddlewareByDoneUseAndUseGlobalDef(t *testing.T) {
|
||||||
|
|
||||||
testResponse(t, app, "/mypath")
|
testResponse(t, app, "/mypath")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUseRouterStopExecution(t *testing.T) {
|
||||||
|
app := iris.New()
|
||||||
|
app.UseRouter(func(ctx iris.Context) {
|
||||||
|
ctx.WriteString("stop")
|
||||||
|
// no ctx.Next, so the router has not even the chance to work.
|
||||||
|
})
|
||||||
|
app.Get("/", writeHandler("index"))
|
||||||
|
|
||||||
|
e := httptest.New(t, app)
|
||||||
|
e.GET("/").Expect().Status(iris.StatusOK).Body().Equal("stop")
|
||||||
|
|
||||||
|
app = iris.New()
|
||||||
|
app.OnErrorCode(iris.StatusForbidden, func(ctx iris.Context) {
|
||||||
|
ctx.Writef("err: %v", ctx.GetErr())
|
||||||
|
})
|
||||||
|
app.UseRouter(func(ctx iris.Context) {
|
||||||
|
ctx.StopWithPlainError(iris.StatusForbidden, fmt.Errorf("custom error"))
|
||||||
|
// stopped but not data written yet, the error code handler
|
||||||
|
// should be responsible of it (use StopWithError to write and close).
|
||||||
|
})
|
||||||
|
app.Get("/", writeHandler("index"))
|
||||||
|
|
||||||
|
e = httptest.New(t, app)
|
||||||
|
e.GET("/").Expect().Status(iris.StatusForbidden).Body().Equal("err: custom error")
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user