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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

custom regex error #1058

Closed
youfu-fun opened this issue Aug 9, 2018 · 5 comments
Closed

custom regex error #1058

youfu-fun opened this issue Aug 9, 2018 · 5 comments
Labels
good first issue A user wrote a good first issue with clear instructions 🤔 type:question

Comments

@youfu-fun
Copy link

Two different regular expressions:

engine.Get(/{alias:string regexp(^[a-z0-9]{1,10})}, Tour)
engine.Get(/{alias:string regexp(^[a-z0-9]{1,10}\\\.xml$)}, PanoXML)

Error:

panic: two or more routes have the same registered path -> GET /{alias:string regexp(^[a-z0-9]{1,10}.xml$)}

@kataras
Copy link
Owner

kataras commented Aug 9, 2018

Yes, you are not allowed to do this. They are, indeed, the same path, the only thing changes is the macro function.

@kataras kataras added good first issue A user wrote a good first issue with clear instructions 🤔 type:question labels Aug 9, 2018
@kataras kataras closed this as completed Aug 9, 2018
@kataras
Copy link
Owner

kataras commented Aug 10, 2018

@youfu9527

Alternative method

package main

import (
   "github.com/kataras/iris"

   "regexp"
   "strconv"
)

func main() {
    engine := iris.New()

    var (
	    expr1 = regexp.MustCompile("^-?[0-9]{1,3}(?:\\.[0-9]{1,10})?$")
	    expr2 = regexp.MustCompile("^[a-z0-9]{1,10}\\.xml$")
    )

    engine.Get("/{alias}", func(ctx iris.Context) {
	    // get the parameter value of "alias" as string to check it against the expressions.
	    alias := ctx.Params().Get("alias")

	    if expr1.MatchString(alias) {
		    /* expr1 possible results:
		    652
		    -08.3520023236
		    -39
		    -420.366988
		    6.4921300
		    ...

		    Convert it as float64, the second value is the "error" which is not necessary here
		    because the regexp you provided it will always match a float representation.
		    */
		    asFloat, _ := strconv.ParseFloat(alias, 64)
		    // or ctx.Params().GetFloat64("alias") inside the `Tour` handler.
		    Tour(ctx, asFloat)
		    return
	    } else if expr2.MatchString(alias) {
		    /* expr2 possible results:
		    td94.xml
		    55zuojv.xml
		    pg88kez.xml
		    k.xml
		    37jeld.xml
		    ...
		    */
		    PanoXML(ctx, alias)
		    return
	    }
	    // else fire status not found.
	    ctx.StatusCode(iris.StatusNotFound)
    })

    engine.Run(iris.Addr(":8080"))
}

func Tour(ctx iris.Context, cord float64) {
	ctx.Writef("Tour: %f", cord)
}

func PanoXML(ctx iris.Context, file string) {
	ctx.Writef("PanoXML: %s", file)
}

Bonus:

If you wanted: /{alias:int} and /{alias:string} you could do that simply as well:

func (ctx iris.Context) {
	aliasAsFloat, err := ctx.Params().GetFloat64("alias")
	if err == nil {
		// it is float.
	        WorkWithFloatHandler(ctx,aliasAsFloat)
		return
	}
        // else it is a string.
       WorkWithStringHandler(ctx.Params().Get("alias"))
}

^ Note that you can call the ctx.Params().GetXXX as many times as you want, it will not have any additional performance penalty, the parameters are stored once request handler is matched once.

@Mrhyuan
Copy link

Mrhyuan commented Mar 18, 2019

Is there any workaround to support this feature or can I solve it by adding some kind of middleware or route interceptor? Thanks. @kataras

@kataras
Copy link
Owner

kataras commented Aug 12, 2019

OK @Mrhyuan, after v11.2.3 Iris is able to handle different parameter types in the same exact path. Read more about it at issue #1315.

In your case, the problem is that you have the same parameter type but the regex expressions differ. I provided you a solution which is good enough if you don't have to repeat these expressions in other routes. If you want a more permant and better solution you can try register a custom parameter for these (Iris is now capable to handle this case too).

Example Code:

package main

import (
	"regexp"

	"github.com/kataras/iris"
)

func registerMacro(app *iris.Application, indent string, expr *regexp.Regexp) {
	app.Macros().Register(indent, indent, false, false, func(paramValue string) (interface{}, bool) {
		ok := expr.MatchString(paramValue)
		if !ok {
			return nil, false
		}

		// You can convert this to any custom parameter, i.e a "Tour" struct,
		// the ctx.Params().Get returns an interface{}
		// so you can cast it to ur custom struct (e.g. Params().Get("tour").(Tour)).
		// But let's keep it simple.
		return paramValue, true
	})
}

func main() {
	app := iris.New()

	// name them as you want, they are your custom parameter types, easy as:
	registerMacro(app, "tour", regexp.MustCompile("^[a-z0-9]{1,10}$"))
	registerMacro(app, "panoxml", regexp.MustCompile("^[a-z0-9]{1,10}\\.xml$"))

	app.Get("/{tour:tour}", Tour)
	app.Get("/{pano:panoxml}", PanoXML)

	app.Run(iris.Addr(":8080"))
}

func Tour(ctx iris.Context) {
	ctx.Writef("Tour Handler with tour = %s", ctx.Params().Get("tour"))
}

func PanoXML(ctx iris.Context) {
	ctx.Writef("PanoXML Handler with pano = %s", ctx.Params().Get("pano"))
}

@kataras
Copy link
Owner

kataras commented Aug 14, 2019

@youfu9527 Actually if you upgrade to the latest iris you can do exactly that you wanted to without the need of registering a custom macro as shown above, the only thing to remember is to keep the same param names:

package main

import "github.com/kataras/iris"

func main() {
	app := iris.New()

	app.Get("/{alias:string regexp(^[a-z0-9]{1,10}\\.xml$)}", PanoXML)
	app.Get("/{alias:string regexp(^[a-z0-9]{1,10}$)}", Tour)

	app.Run(iris.Addr(":8080"))
}

func Tour(ctx iris.Context) {
	ctx.Writef("Tour Handler with alias = %s", ctx.Params().Get("alias"))
}

func PanoXML(ctx iris.Context) {
	ctx.Writef("PanoXML Handler with alias= %s", ctx.Params().Get("alias"))
}

github-actions bot pushed a commit to goproxies/github.com-kataras-iris that referenced this issue Jul 27, 2020
…well, a use case: kataras#1058

Former-commit-id: e7dcc5c0d9a2e3569e0f49303ff342bb8748baf5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue A user wrote a good first issue with clear instructions 🤔 type:question
Projects
None yet
Development

No branches or pull requests

3 participants