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

When I used router in my codes, found some strange rule that maybe need to ask for help about it. #1349

Closed
conero opened this issue Aug 29, 2019 · 3 comments

Comments

@conero
Copy link

conero commented Aug 29, 2019

Code like this:

package main

package main
// ...
// register the router
mvc.New(server.Party("/api/data/{model:string}/{action:string}")).
		Handle(new(api.Data))

package api

package api
// handler in controller
type Data struct{
	Model  string
	Action string
	Id     string
}

func (c *Data) BeforeActivation(b mvc.BeforeActivation) {
	// @todo [error] c.Ctx = nil; so made the `dataInit()`
	//c.Model = c.Ctx.Params().Get("model")
	//c.Action = c.Ctx.Params().Get("action")
	//c.Id = c.Ctx.Params().Get("id")
}

// ...
func (c *Data) dataInit() {
	c.Model = c.Ctx.Params().Get("model")
	c.Action = c.Ctx.Params().Get("action")
	c.Id = c.Ctx.Params().Get("id")
}

// {url}/id
func (c *Data) AnyBy(id string) {
	c.dataInit()
	vdata := map[string]interface{}{
		"mode":         strings.ToUpper(c.Model),
		"action":       strings.ToUpper(c.Action),
		"tmp":          c.Id,
		"list":         c.Ctx.Path(),
		"id":           path.Base(c.Ctx.Path()),
		"param_id":     id,
		"iris-version": iris.Version,
	}
	c.Ctx.JSON(vdata)
}

Then made the request:
GET: http://127.0.0.1:9960/api/data/user/list/2099

Get response

{
    "action": "TEST",
    "id": "2099",
    "iris-version": "11.2.8",
    "list": "/api/data/user/test/2099",
    "mode": "USER",
    "param_id": "user",
    "tmp": ""
}

Problem in this case:

  1. AnyBy(id string) id should be 2099, but user
  2. c.Ctx.Params().Get("id") is empty mayby should be 2099
  3. func (c *Data) BeforeActivation(b mvc.BeforeActivation) c.Ctx is nil

So I had to use path.Base to get the true id, I don't know if I missed some thing but the help.

@kataras
Copy link
Owner

kataras commented Aug 30, 2019

Hello @conero ,

The ctx.Params().Get("id") is empty because you didn't declare it anywhere as path parameter in your route. The AnyBy(id string) does not mean that the path parameter's name is "id", go's reflection does not have a way to read the input parameter's names. If you need to take that id value from ctx.Params(). then you need to take it by parameter index instead: entry, ok := c.Ctx.Params().GetEntryAt(index) or .Params().Get("param0 or param1 and etc") and etc. However you don't need to do this: just access it via the input parameter at your controller's method, in your case it's the id.

Example:

1. Data.AnyBy(s string) resolves to All methods: /api/data/{model:string}/{action:string}/{param1:string}

mvc.New(app.Party("/api/data/{model:string}/{action:string}")).Handle(new(Data))
// [...]
func (c *Data) AnyBy(s string) {
}
  1. Use AfterActivation instead to have access to the bind-ed fields, the BeforeActivation can be used to change the binding values and etc.

TIP: use app/server.Logger().SetLevel("debug") to see the resolved dependencies and the routes registered.

UPDATE: The issue you are facing is coming from the fact that you register a Party with parameters that should be handled inside the controller, so the AnyBy is getting the first parameter, which is the "model" instead of the correct one, which is a BUG and it will be fixed today. However you can also do this (which outputs the expected result):

mvc.New(app.Party("/api/data").Handle(new(Data))
// [...]
func (c *Data) AnyBy(model, action, id string) {
	c.Model = model
	c.Action = action
	// c.ID = c.Ctx.Params().Get("param1")
	c.ID = id
	c.Ctx.Writef("%#+v\n", c)
}

TIP 2: You can also bind dynamic function which will set your model on every controller, based on the context, e.g.

var userDependency = func(ctx iris.Context) *user {
name := strings.Title(ctx.Params().Get("name"))
for _, u := range usersSample {
if u.Name == name {
return u
}
}
// you may want or no to handle the error here, either way the main route handler
// is going to be executed, always. A dynamic dependency(per-request) is not a middleware, so things like `ctx.Next()` or `ctx.StopExecution()`
// do not apply here, look the `getUserHandler`'s first lines; we stop/exit the handler manually
// if the received user is nil but depending on your app's needs, it is possible to do other things too.
// A dynamic dependency like this can return more output values, i.e (*user, bool).
fail(ctx, iris.StatusNotFound, "user with name '%s' not found", name)
return nil
}

@conero
Copy link
Author

conero commented Sep 2, 2019

Big thanks to @kataras, bro.

@conero conero closed this as completed Sep 2, 2019
kataras added a commit that referenced this issue Sep 7, 2019
@kataras
Copy link
Owner

kataras commented Sep 7, 2019

You are welcome @conero, sorry for the delay, I had some interviews to do. I've just pushed a commit which supports the above case you posted as well.

github-actions bot pushed a commit to goproxies/github.com-kataras-iris that referenced this issue Jul 27, 2020
Former-commit-id: 1e2c7185fc3c536ceb8b269c75b9a2c19323960b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants