diff --git a/_examples/README.md b/_examples/README.md index 3f689aef..2592cd24 100644 --- a/_examples/README.md +++ b/_examples/README.md @@ -59,6 +59,7 @@ * [From func(http.HandlerFunc) http.HandlerFunc](convert-handlers/real-usecase-raven/writing-middleware/main.go) * [Rewrite Middleware](routing/rewrite/main.go) * [Route State](routing/route-state/main.go) + * [Remove Route](routing/remove-route/main.go) * [Reverse Routing](routing/reverse/main.go) * [Router Wrapper](routing/custom-wrapper/main.go) * [Custom Router](routing/custom-router/main.go) diff --git a/_examples/mvc/hello-world/main.go b/_examples/mvc/hello-world/main.go index 4b3ce6bd..0cd9b8d6 100644 --- a/_examples/mvc/hello-world/main.go +++ b/_examples/mvc/hello-world/main.go @@ -1,11 +1,12 @@ package main import ( + "strings" + "github.com/kataras/iris/v12" "github.com/kataras/iris/v12/middleware/logger" "github.com/kataras/iris/v12/middleware/recover" "github.com/kataras/iris/v12/mvc" - "strings" ) // This example is equivalent to the @@ -47,7 +48,7 @@ func newApp() *iris.Application { w = strings.ToLower(w) } path += w - return path + return path }).Handle(new(ExampleControllerCustomPath)) return app @@ -131,7 +132,6 @@ func (c *ExampleControllerCustomPath) GetHelloWorld() interface{} { return map[string]string{"message": "Hello Iris! CustomPath"} } - // GetUserBy serves // Method: GET // Resource: http://localhost:8080/user/{username:string} diff --git a/_examples/routing/remove-route/main.go b/_examples/routing/remove-route/main.go new file mode 100644 index 00000000..8c684ca1 --- /dev/null +++ b/_examples/routing/remove-route/main.go @@ -0,0 +1,24 @@ +package main + +import ( + "github.com/kataras/iris/v12" +) + +func main() { + app := iris.New() + app.Get("/", index) + app.Get("/about", about).SetName("about_page") + app.RemoveRoute("about_page") + + // http://localhost:8080 + // http://localhost:8080/about (Not Found) + app.Listen(":8080") +} + +func index(ctx iris.Context) { + ctx.WriteString("Hello, Gophers!") +} + +func about(ctx iris.Context) { + ctx.HTML("

About Page

") +} diff --git a/core/router/api_builder.go b/core/router/api_builder.go index d1f32dd6..7f23294e 100644 --- a/core/router/api_builder.go +++ b/core/router/api_builder.go @@ -43,7 +43,7 @@ var AllMethods = []string{ // all the routes. type repository struct { routes []*Route - pos map[string]int + paths map[string]*Route // only the fullname path part, required at CreateRoutes for registering index page. } func (repo *repository) get(routeName string) *Route { @@ -70,12 +70,8 @@ func (repo *repository) getRelative(r *Route) *Route { } func (repo *repository) getByPath(tmplPath string) *Route { - if repo.pos != nil { - if idx, ok := repo.pos[tmplPath]; ok { - if len(repo.routes) > idx { - return repo.routes[idx] - } - } + if r, ok := repo.paths[tmplPath]; ok { + return r } return nil @@ -85,6 +81,25 @@ func (repo *repository) getAll() []*Route { return repo.routes } +func (repo *repository) remove(routeName string) bool { + for i, r := range repo.routes { + if r.Name == routeName { + lastIdx := len(repo.routes) - 1 + if lastIdx == i { + repo.routes = repo.routes[0:lastIdx] + } else { + cp := make([]*Route, 0, lastIdx) + cp = append(cp, repo.routes[:i]...) + repo.routes = append(cp, repo.routes[i+1:]...) + } + + delete(repo.paths, r.tmpl.Src) + return true + } + } + return false +} + func (repo *repository) register(route *Route, rule RouteRegisterRule) (*Route, error) { for i, r := range repo.routes { // 14 August 2019 allow register same path pattern with different macro functions, @@ -110,10 +125,10 @@ func (repo *repository) register(route *Route, rule RouteRegisterRule) (*Route, repo.routes = append(repo.routes, route) if route.StatusCode == 0 { // a common resource route, not a status code error handler. - if repo.pos == nil { - repo.pos = make(map[string]int) + if repo.paths == nil { + repo.paths = make(map[string]*Route) } - repo.pos[route.tmpl.Src] = len(repo.routes) - 1 + repo.paths[route.tmpl.Src] = route } return route, nil @@ -641,6 +656,17 @@ func (api *APIBuilder) CreateRoutes(methods []string, relativePath string, handl return api.createRoutes(0, methods, relativePath, handlers...) } +// RemoveRoute deletes a registered route by its name before `Application.Listen`. +// The default naming for newly created routes is: method + subdomain + path. +// Reports whether a route with that name was found and removed successfully. +// +// Note that this method applies to all Parties (sub routers) +// even if each of the Parties have access to this method, +// as the route name is unique per Iris Application. +func (api *APIBuilder) RemoveRoute(routeName string) bool { + return api.routes.remove(routeName) +} + func (api *APIBuilder) createRoutes(errorCode int, methods []string, relativePath string, handlers ...context.Handler) []*Route { if statusCodeSuccessful(errorCode) { errorCode = 0 @@ -808,7 +834,7 @@ func (api *APIBuilder) Party(relativePath string, handlers ...context.Handler) P copy(allowMethods, api.allowMethods) // make a copy of the parent properties. - var properties context.Map + properties := make(context.Map, len(api.properties)) for k, v := range api.properties { properties[k] = v } @@ -924,11 +950,6 @@ func (api *APIBuilder) PartyConfigure(relativePath string, partyReg ...PartyConf return child } -func (api *APIBuilder) configureParty(partyReg ...PartyConfigurator) Party { - - return api -} - // Subdomain returns a new party which is responsible to register routes to // this specific "subdomain". // diff --git a/core/router/party.go b/core/router/party.go index d3d5ebf5..f4c487f5 100644 --- a/core/router/party.go +++ b/core/router/party.go @@ -388,6 +388,15 @@ type Party interface { // This method can be used for third-parties Iris helpers packages and tools // that want a more detailed view of Party-based Routes before take the decision to register them. CreateRoutes(methods []string, relativePath string, handlers ...context.Handler) []*Route + // RemoveRoute deletes a registered route by its name before `Application.Listen`. + // The default naming for newly created routes is: method + subdomain + path. + // Reports whether a route with that name was found and removed successfully. + // + // Note that this method applies to all Parties (sub routers) + // even if each of the Parties have access to this method, + // as the route name is unique per Iris Application. + RemoveRoute(routeName string) bool + // StaticContent registers a GET and HEAD method routes to the requestPath // that are ready to serve raw static bytes, memory cached. // diff --git a/core/router/route.go b/core/router/route.go index c78ba3ce..f35e2a98 100644 --- a/core/router/route.go +++ b/core/router/route.go @@ -294,6 +294,16 @@ func (r *Route) DeepEqual(other *Route) bool { return r.Equal(other) && r.tmpl.Src == other.tmpl.Src } +// SetName overrides the default route name which defaults to +// method + subdomain + path and +// statusErrorCode_method+subdomain+path for error routes. +// +// Note that the route name MUST BE unique per Iris Application. +func (r *Route) SetName(newRouteName string) *Route { + r.Name = newRouteName + return r +} + // ExcludeSitemap excludes this route page from sitemap generator. // It sets the NoSitemap field to true. //