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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

馃敟 Feature: Add ability to restart route handling #1739

Merged
merged 2 commits into from Feb 3, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions ctx.go
Expand Up @@ -782,6 +782,14 @@ func (c *Ctx) Next() (err error) {
return err
}

// RestartRouting instead of going to the next handler. This may be usefull after
// changing the request path. Note that handlers might be executed again.
func (c *Ctx) RestartRouting() error {
c.indexRoute = -1
_, err := c.app.next(c)
return err
}

// OriginalURL contains the original request URL.
// Returned value is only valid within the handler. Do not store any references.
// Make copies or use the Immutable setting to use the value outside the Handler.
Expand Down
63 changes: 63 additions & 0 deletions ctx_test.go
Expand Up @@ -2065,6 +2065,69 @@ func Test_Ctx_RenderWithLocalsAndBinding(t *testing.T) {
utils.AssertEqual(t, "<h1>Hello, World!</h1>", string(c.Response().Body()))
}

// go test -run Test_Ctx_Restart
func Test_Ctx_Restart(t *testing.T) {
app := New()
calls := 0
app.Get("/", func(c *Ctx) error {
calls++
if calls < 3 {
return c.RestartRouting()
}
return nil
})
resp, err := app.Test(httptest.NewRequest(MethodGet, "http://example.com/", nil))
utils.AssertEqual(t, nil, err, "app.Test(req)")
utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
utils.AssertEqual(t, 3, calls, "Number of calls")
}

// go test -run Test_Ctx_RestartWithChangedPath
func Test_Ctx_RestartWithChangedPath(t *testing.T) {
app := New()
executedOldHandler := false
executedNewHandler := false

app.Get("/old", func(c *Ctx) error {
c.Path("/new")
return c.RestartRouting()
})
app.Get("/old", func(c *Ctx) error {
executedOldHandler = true
return nil
})
app.Get("/new", func(c *Ctx) error {
executedNewHandler = true
return nil
})

resp, err := app.Test(httptest.NewRequest(MethodGet, "http://example.com/old", nil))
utils.AssertEqual(t, nil, err, "app.Test(req)")
utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
utils.AssertEqual(t, false, executedOldHandler, "Executed old handler")
utils.AssertEqual(t, true, executedNewHandler, "Executed new handler")
}

// go test -run Test_Ctx_RestartWithChangedPathAnd404
func Test_Ctx_RestartWithChangedPathAndCatchAll(t *testing.T) {
app := New()
app.Get("/new", func(c *Ctx) error {
return nil
})
app.Use(func(c *Ctx) error {
c.Path("/new")
// c.Next() would fail this test as a 404 is returned from the next handler
return c.RestartRouting()
})
app.Use(func(c *Ctx) error {
return ErrNotFound
})

resp, err := app.Test(httptest.NewRequest(MethodGet, "http://example.com/old", nil))
utils.AssertEqual(t, nil, err, "app.Test(req)")
utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
}

type testTemplateEngine struct {
templates *template.Template
}
Expand Down