Open ghost opened 9 years ago
For implementation of #1 it will be necessary to modify "magic methods" (Initially
and Finally
). I don't want to introduce a new one, so they will have the signature:
func (c *Controller) Initially(http.ResponseWriter, *http.Request, map[string]string) bool
instead of the one they have now. The third argument will be used for passing current controller and action names from generated handler to the action (we are not using reflection, right?). The only concern is a use of map
for passing just 2 arguments. Probably, []string
is a better option or even []interface{}
.
So, after the change code above (in the previous comment) will look like:
func AppIndex(w http.ResponseWriter, r *http.Request) {
...
defer c.Finally(w, r, []interface{}{"App", "Index"})
...
}
"Fields binding" has been implemented. Related info: https://github.com/colegion/goal/issues/37#issuecomment-179391953
Now it's possible to get request, response, current action name or controller name by creating a field with special tag in your controller:
type Controller struct {
MyRequest http.Request `bind:"request"`
MyResponseWriter http.ResponseWriter `bind:"response"`
MyAction string `bind:"action"`
MyController string `bind:"controller"`
}
Name of the field doesn't matter but it must be exported (i.e. Request
, not request
).
"Magic" Initially
and Finally
methods have been removed. Now there is only Before
and After
actions. But After
works as Finally
, i.e. it is called even if Before
or SomeAction
return non-nil result.
func (c *App) Before() http.Handler {
println("Started first...")
return nil
}
func (c *App) Index() http.Handler {
println("Started if 'Before' returned nil...")
return c.Render()
}
func (c *App) After() http.Handler {
println("Started at the end...")
return nil
}
In future versions I want to remove "fields binding" that are described in the comment above and use a standard binding mechanism for them. For illustration, now it's possible to bind parameters as follows:
func (c *App) Greet(name string) http.Handler
A limited number of types are supported (e.g. int
, string
, float32
, etc.).
The plan is to add support of http.Request
, http.ResponseWriter
for Request
and Response
.
The question is what to do with "current action name" and "current controller name", they are both of type string
. I don't want to make user import custom packages. So, probably the following approach will be taken:
type action string
type controller string
func (c *App) Index(currentAction action, currentController controller) http.Handler {
}
Variables of type action
and controller
will be binded to current action/controller values if the types are custom types based on strings.
What's the difference between Initially and Before, like others Filter?
Use case such as Access controller before a certain controller instance?
@xpbliss Initially
was a method that required specific input arguments (if you miss one of them the whole method was ignored):
func (c *App) Initially(http.ResponseWriter, *http.Request, as []string) bool {
}
It was used for passing Request
, Response
, and current action / controller name from handler function to your controller.
Before
is a regular action. I.e. it can take any arguments (that are automatically binded) and returns http.Handler
as the first result:
func (c *App) Before(name string, page int) http.Handler {
}
Apart from that there were no differences. And "bind" struct tags are used for passing arguments to controller now. That's why Initially
was removed and now there is only Before
.
This issue is created to discuss the controllers: current state and what changes are needed (e.g. for #1).
Controllers are described here and actions here.
Controller
Any
struct
type that has actions is a controller.Action
Any exported method of a controller that returns
http.Handler
as a first argument.Magic actions: Before and After
Just like regular actions but are executed automatically before / after every action of their controller.
Arguments and results
Actions may expect any number of arguments of builtin types and return as many results as necessary.
The arguments will be taken from (in that order):
/:path
parameters (if default's router is used).?query
parameters.Magic methods: Initially and Finally
https://github.com/colegion/goal/blob/gh-pages/manual/handlers/controllers.md#magic-methods
Initially
is started before any action andFinally
after. Moreover,Finally
usesdefer
, so it will be started no matter what (i.e. even in case of action's panic).Controller hierarchy
https://github.com/colegion/goal/blob/gh-pages/manual/handlers/controllers.md#inheritance
Child controller will inherit magic methods and magic actions of its parent controllers.
Code generation
To illustrate the idea of
handlers
package generation here is an example. If we have the followingcontrollers
package:we'll get the
handlers
package generated (actually it will be a bit more complex /here's an actual one/, but for clarity it was simplified):