Implement a GetURI to get the full uri of a (named) route

This commit is contained in:
Makis Maropoulos 2016-06-02 19:22:36 +03:00
parent 79e984146e
commit 05b6723b19
5 changed files with 68 additions and 3 deletions

View File

@ -100,6 +100,7 @@ type (
// SetHeader sets the response headers first parameter is the key, second is the value
SetHeader(string, string)
Redirect(string, ...int)
RedirectTo(routeName string, args ...interface{})
// Errors
NotFound()
Panic()

View File

@ -13,9 +13,9 @@ func (ctx *Context) SetHeader(k string, v string) {
// Redirect redirect sends a redirect response the client
// accepts 2 parameters string and an optional int
// first parameter is the url to redirect
// second parameter is the http status should send, default is 302 (Temporary redirect), you can set it to 301 (Permant redirect), if that's nessecery
// second parameter is the http status should send, default is 307 (Temporary redirect), you can set it to 301 (Permant redirect), if that's nessecery
func (ctx *Context) Redirect(urlToRedirect string, statusHeader ...int) {
httpStatus := 302 // temporary redirect
httpStatus := StatusTemporaryRedirect // temporary redirect
if statusHeader != nil && len(statusHeader) > 0 && statusHeader[0] > 0 {
httpStatus = statusHeader[0]
}
@ -24,6 +24,15 @@ func (ctx *Context) Redirect(urlToRedirect string, statusHeader ...int) {
ctx.StopExecution()
}
// RedirectTo does the same thing as Redirect but instead of receiving a uri or path it receives a route name
func (ctx *Context) RedirectTo(routeName string, args ...interface{}) {
s, ok := ctx.station.RouteByName(routeName).Parse(args...)
if ok {
ctx.Redirect(s, StatusTemporaryRedirect)
}
}
// Error handling
// NotFound emits an error 404 to the client, using the custom http errors

View File

@ -247,6 +247,9 @@ func (s *Iris) PreListen(opt config.Server) *server.Server {
func (s *Iris) PostListen() {
//if not error opening the server, then:
// prepare the route actions, these actions needs real server's access because that it's after server's listen
s.router.optimizeLookups()
//set the rest (for Data, Text, JSON, JSONP, XML)
s.rest = rest.New(s.config.Render.Rest)
// set the templates

View File

@ -18,9 +18,18 @@ type (
Name(string) IRoute
GetMiddleware() Middleware
HasCors() bool
// internal methods
setTLS(bool)
setHost(string)
//
// used to check arguments with the route's named parameters and return the correct url
// second parameter is false when the action cannot be done
Parse(...interface{}) (string, bool)
// GetURI returns the GetDomain() + Parse(...optional named parameters if route is dynamic)
// instead of Parse it just returns an empty string if path parse is failed
GetURI(...interface{}) string
}
// RouteNameFunc is returned to from route handle
@ -34,7 +43,10 @@ type (
// the name of the route, the default name is just the registed path.
name string
middleware Middleware
// if true then https://
isTLS bool
// the real host
host string
// this is used to convert /mypath/:aparam/:something to -> /mypath/%v/%v and /mypath/* -> mypath/%v
// we use %v to escape from the conversions between strings,booleans and integers.
// used inside custom html template func 'url'
@ -149,6 +161,14 @@ func (r *Route) HasCors() bool {
return RouteConflicts(r, "httpmethod")
}
func (r *Route) setTLS(isSecure bool) {
r.isTLS = isSecure
}
func (r *Route) setHost(s string) {
r.host = s
}
func (r *Route) Parse(args ...interface{}) (string, bool) {
// check if arguments are not equal to the named parameters ( : = 1, * = all named parameters split to / ), if this happens then send not found err
///TODO: I'm thinking of making an option to disable these checks and just return a result, because they have cost when rendering an html/template, not too big compared to the render action but... we will see
@ -190,6 +210,21 @@ func (r *Route) Parse(args ...interface{}) (string, bool) {
return fmt.Sprintf(r.formattedPath, args...), true
}
func (r *Route) GetURI(args ...interface{}) (uri string) {
scheme := "http://"
if r.isTLS {
scheme = "https://"
}
host := r.host
if parsedPath, ok := r.Parse(args...); ok {
uri = scheme + host + parsedPath
}
return
}
// RouteConflicts checks for route's middleware conflicts
func RouteConflicts(r *Route, with string) bool {
for _, h := range r.middleware {

View File

@ -215,6 +215,23 @@ func (r *router) optimize() {
r.optimized = true
}
// optimizeLookups runs AFTER server's listen
func (r *router) optimizeLookups() {
// set the isTLS on all routes and the correct full domain (if it's local its empty but we don't want that) ( we don't use Domain because it's used to the tree)
listeningHost := r.station.server.Listener().Addr().String()
for idx, _ := range r.lookups {
theR := r.lookups[idx]
theR.setTLS(r.station.server.IsSecure())
if theR.GetDomain() == "" { // means local, no subdomain
theR.setHost(listeningHost)
} else {
// it's a subdomain route
theR.setHost(theR.GetDomain() + "." + listeningHost)
}
}
}
// notFound internal method, it justs takes the context from pool ( in order to have the custom errors available) and procedure a Not Found 404 error
// this is being called when no route was found used on the ServeRequest.
func (r *router) notFound(reqCtx *fasthttp.RequestCtx) {