mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01:00
update the documents for the new MVC API and some of its new features but not finished yet, README big examples and _examples/mvc/login is are yet updated and I'm thinking of removing the big examples on README.md, they exist on the _examples/mvc updated.
Former-commit-id: c2938d4bcaa3520744526f7975ee3cce632499b3
This commit is contained in:
parent
91ee8287a8
commit
ef3a09c126
|
@ -2,7 +2,7 @@ package controllers
|
||||||
|
|
||||||
import "github.com/kataras/iris/mvc"
|
import "github.com/kataras/iris/mvc"
|
||||||
|
|
||||||
type HomeController struct{ mvc.C }
|
type HomeController struct{}
|
||||||
|
|
||||||
func (c *HomeController) Get() mvc.Result {
|
func (c *HomeController) Get() mvc.Result {
|
||||||
return mvc.View{Name: "index.html"}
|
return mvc.View{Name: "index.html"}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/kataras/iris"
|
"github.com/kataras/iris"
|
||||||
"github.com/kataras/iris/context"
|
"github.com/kataras/iris/context"
|
||||||
|
"github.com/kataras/iris/mvc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -17,21 +18,13 @@ const (
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
app.Configure(configure)
|
|
||||||
|
|
||||||
// app.Controller("/", new(controllers.IndexController))
|
|
||||||
// app.Controller("/about", new(controllers.AboutController))
|
|
||||||
// app.Controller("/contact", new(controllers.ContactController))
|
|
||||||
|
|
||||||
app.Controller("/", new(controllers.HomeController))
|
|
||||||
|
|
||||||
app.Run(iris.Addr(":5000"), iris.WithoutVersionChecker)
|
|
||||||
}
|
|
||||||
|
|
||||||
func configure(app *iris.Application) {
|
|
||||||
app.RegisterView(iris.HTML("./views", ".html").Layout("shared/layout.html"))
|
app.RegisterView(iris.HTML("./views", ".html").Layout("shared/layout.html"))
|
||||||
app.StaticWeb("/public", publicDir)
|
app.StaticWeb("/public", publicDir)
|
||||||
app.OnAnyErrorCode(onError)
|
app.OnAnyErrorCode(onError)
|
||||||
|
|
||||||
|
mvc.New(app).Register(new(controllers.HomeController))
|
||||||
|
|
||||||
|
app.Run(iris.Addr(":5000"), iris.WithoutVersionChecker)
|
||||||
}
|
}
|
||||||
|
|
||||||
type err struct {
|
type err struct {
|
||||||
|
|
|
@ -125,43 +125,83 @@ with the fastest possible execution.
|
||||||
|
|
||||||
All HTTP Methods are supported, for example if want to serve `GET`
|
All HTTP Methods are supported, for example if want to serve `GET`
|
||||||
then the controller should have a function named `Get()`,
|
then the controller should have a function named `Get()`,
|
||||||
you can define more than one method function to serve in the same Controller struct.
|
you can define more than one method function to serve in the same Controller.
|
||||||
|
|
||||||
|
Register custom controller's struct's methods as handlers with custom paths(even with regex parametermized path)
|
||||||
|
via the `BeforeActivation` custom event callback, per-controller. Example:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/kataras/iris"
|
||||||
|
"github.com/kataras/iris/mvc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := iris.New()
|
||||||
|
mvc.Configure(app.Party("/root"), myMVC)
|
||||||
|
app.Run(iris.Addr(":8080"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func myMVC(app *mvc.Application) {
|
||||||
|
// app.AddDependencies(...)
|
||||||
|
// app.Router.Use/UseGlobal/Done(...)
|
||||||
|
app.Register(new(MyController))
|
||||||
|
}
|
||||||
|
|
||||||
|
type MyController struct {}
|
||||||
|
|
||||||
|
func (m *MyController) BeforeActivation(b mvc.BeforeActivation) {
|
||||||
|
// b.Dependencies().Add/Remove
|
||||||
|
// b.Router().Use/UseGlobal/Done // and any standard API call you already know
|
||||||
|
|
||||||
|
// 1-> Method
|
||||||
|
// 2-> Path
|
||||||
|
// 3-> The controller's function name to be parsed as handler
|
||||||
|
// 4-> Any handlers that should run before the MyCustomHandler
|
||||||
|
b.Handle("GET", "/something/{id:long}", "MyCustomHandler", anyMiddleware...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: http://localhost:8080/root
|
||||||
|
func (m *MyController) Get() string { return "Hey" }
|
||||||
|
|
||||||
|
// GET: http://localhost:8080/root/something/{id:long}
|
||||||
|
func (m *MyController) MyCustomHandler(id int64) string { return "MyCustomHandler says Hey" }
|
||||||
|
```
|
||||||
|
|
||||||
Persistence data inside your Controller struct (share data between requests)
|
Persistence data inside your Controller struct (share data between requests)
|
||||||
via `iris:"persistence"` tag right to the field or Bind using `app.Controller("/" , new(myController), theBindValue)`.
|
by defining services to the Dependencies or have a `Singleton` controller scope.
|
||||||
|
|
||||||
Models inside your Controller struct (set-ed at the Method function and rendered by the View)
|
Share the dependencies between controllers or register them on a parent MVC Application, and ability
|
||||||
via `iris:"model"` tag right to the field, i.e ```User UserModel `iris:"model" name:"user"` ``` view will recognise it as `{{.user}}`.
|
to modify dependencies per-controller on the `BeforeActivation` optional event callback inside a Controller,
|
||||||
If `name` tag is missing then it takes the field's name, in this case the `"User"`.
|
i.e `func(c *MyController) BeforeActivation(b mvc.BeforeActivation) { b.Dependencies().Add/Remove(...) }`.
|
||||||
|
|
||||||
Access to the request path and its parameters via the `Path and Params` fields.
|
Access to the `Context` as a controller's field(no manual binding is neede) i.e `Ctx iris.Context` or via a method's input argument, i.e `func(ctx iris.Context, otherArguments...)`.
|
||||||
|
|
||||||
Access to the template file that should be rendered via the `Tmpl` field.
|
Models inside your Controller struct (set-ed at the Method function and rendered by the View).
|
||||||
|
You can return models from a controller's method or set a field in the request lifecycle
|
||||||
|
and return that field to another method, in the same request lifecycle.
|
||||||
|
|
||||||
Access to the template data that should be rendered inside
|
Flow as you used to, mvc application has its own `Router` which is a type of `iris/router.Party`, the standard iris api.
|
||||||
the template file via `Data` field.
|
`Controllers` can be registered to any `Party`, including Subdomains, the Party's begin and done handlers work as expected.
|
||||||
|
|
||||||
Access to the template layout via the `Layout` field.
|
|
||||||
|
|
||||||
Access to the low-level `iris.Context/context.Context` via the `Ctx` field.
|
|
||||||
|
|
||||||
Flow as you used to, `Controllers` can be registered to any `Party`,
|
|
||||||
including Subdomains, the Party's begin and done handlers work as expected.
|
|
||||||
|
|
||||||
Optional `BeginRequest(ctx)` function to perform any initialization before the method execution,
|
Optional `BeginRequest(ctx)` function to perform any initialization before the method execution,
|
||||||
useful to call middlewares or when many methods use the same collection of data.
|
useful to call middlewares or when many methods use the same collection of data.
|
||||||
|
|
||||||
Optional `EndRequest(ctx)` function to perform any finalization after any method executed.
|
Optional `EndRequest(ctx)` function to perform any finalization after any method executed.
|
||||||
|
|
||||||
Inheritance, see for example our `mvc.SessionController`, it has the `mvc.Controller` as an embedded field
|
Inheritance, recursively, see for example our `mvc.SessionController`, it has the `Session *sessions.Session` and `Manager *sessions.Sessions` as embedded fields
|
||||||
and it adds its logic to its `BeginRequest`, [here](https://github.com/kataras/iris/blob/master/mvc/session_controller.go).
|
which are filled by its `BeginRequest`, [here](https://github.com/kataras/iris/blob/master/mvc/session_controller.go).
|
||||||
|
This is just an example, you could use the `mvc.Session(mySessions)` as a dependency to the MVC Application, i.e
|
||||||
|
`mvcApp.AddDependencies(mvc.Session(sessions.New(sessions.Config{Cookie: "iris_session_id"})))`.
|
||||||
|
|
||||||
Register one or more relative paths and able to get path parameters, i.e
|
Access to the dynamic path parameters via the controller's methods' input arguments, no binding is needed.
|
||||||
|
When you use the Iris' default syntax to parse handlers from a controller, you need to suffix the methods
|
||||||
|
with the `By` word, uppercase is a new sub path. Example:
|
||||||
|
|
||||||
If `app.Controller("/user", new(user.Controller))`
|
If `mvc.New(app.Party("/user")).Register(new(user.Controller))`
|
||||||
|
|
||||||
- `func(*Controller) Get()` - `GET:/user` , as usual.
|
- `func(*Controller) Get()` - `GET:/user`.
|
||||||
- `func(*Controller) Post()` - `POST:/user`, as usual.
|
- `func(*Controller) Post()` - `POST:/user`.
|
||||||
- `func(*Controller) GetLogin()` - `GET:/user/login`
|
- `func(*Controller) GetLogin()` - `GET:/user/login`
|
||||||
- `func(*Controller) PostLogin()` - `POST:/user/login`
|
- `func(*Controller) PostLogin()` - `POST:/user/login`
|
||||||
- `func(*Controller) GetProfileFollowers()` - `GET:/user/profile/followers`
|
- `func(*Controller) GetProfileFollowers()` - `GET:/user/profile/followers`
|
||||||
|
@ -169,11 +209,11 @@ If `app.Controller("/user", new(user.Controller))`
|
||||||
- `func(*Controller) GetBy(id int64)` - `GET:/user/{param:long}`
|
- `func(*Controller) GetBy(id int64)` - `GET:/user/{param:long}`
|
||||||
- `func(*Controller) PostBy(id int64)` - `POST:/user/{param:long}`
|
- `func(*Controller) PostBy(id int64)` - `POST:/user/{param:long}`
|
||||||
|
|
||||||
If `app.Controller("/profile", new(profile.Controller))`
|
If `mvc.New(app.Party("/profile")).Register(new(profile.Controller))`
|
||||||
|
|
||||||
- `func(*Controller) GetBy(username string)` - `GET:/profile/{param:string}`
|
- `func(*Controller) GetBy(username string)` - `GET:/profile/{param:string}`
|
||||||
|
|
||||||
If `app.Controller("/assets", new(file.Controller))`
|
If `mvc.New(app.Party("/assets")).Register(new(file.Controller))`
|
||||||
|
|
||||||
- `func(*Controller) GetByWildard(path string)` - `GET:/assets/{param:path}`
|
- `func(*Controller) GetByWildard(path string)` - `GET:/assets/{param:path}`
|
||||||
|
|
||||||
|
@ -188,21 +228,19 @@ func(c *ExampleController) Get() string |
|
||||||
int |
|
int |
|
||||||
(int, string) |
|
(int, string) |
|
||||||
(string, error) |
|
(string, error) |
|
||||||
bool |
|
|
||||||
(any, bool) |
|
|
||||||
(bool, any) |
|
|
||||||
error |
|
error |
|
||||||
(int, error) |
|
(int, error) |
|
||||||
|
(any, bool) |
|
||||||
(customStruct, error) |
|
(customStruct, error) |
|
||||||
customStruct |
|
customStruct |
|
||||||
(customStruct, int) |
|
(customStruct, int) |
|
||||||
(customStruct, string) |
|
(customStruct, string) |
|
||||||
mvc.Result or (mvc.Result, error) and so on...
|
mvc.Result or (mvc.Result, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
where [mvc.Result](https://github.com/kataras/iris/blob/master/mvc/method_result.go) is an interface which contains only that function: `Dispatch(ctx iris.Context)`.
|
where [mvc.Result](https://github.com/kataras/iris/blob/master/mvc/func_result.go) is an interface which contains only that function: `Dispatch(ctx iris.Context)`.
|
||||||
|
|
||||||
**Using Iris MVC for code reuse**
|
## Using Iris MVC for code reuse
|
||||||
|
|
||||||
By creating components that are independent of one another, developers are able to reuse components quickly and easily in other applications. The same (or similar) view for one application can be refactored for another application with different data because the view is simply handling how the data is being displayed to the user.
|
By creating components that are independent of one another, developers are able to reuse components quickly and easily in other applications. The same (or similar) view for one application can be refactored for another application with different data because the view is simply handling how the data is being displayed to the user.
|
||||||
|
|
||||||
|
|
|
@ -12,49 +12,83 @@ with the fastest possible execution.
|
||||||
|
|
||||||
All HTTP Methods are supported, for example if want to serve `GET`
|
All HTTP Methods are supported, for example if want to serve `GET`
|
||||||
then the controller should have a function named `Get()`,
|
then the controller should have a function named `Get()`,
|
||||||
you can define more than one method function to serve in the same Controller struct.
|
you can define more than one method function to serve in the same Controller.
|
||||||
|
|
||||||
|
Register custom controller's struct's methods as handlers with custom paths(even with regex parametermized path)
|
||||||
|
via the `BeforeActivation` custom event callback, per-controller. Example:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/kataras/iris"
|
||||||
|
"github.com/kataras/iris/mvc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := iris.New()
|
||||||
|
mvc.Configure(app.Party("/root"), myMVC)
|
||||||
|
app.Run(iris.Addr(":8080"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func myMVC(app *mvc.Application) {
|
||||||
|
// app.AddDependencies(...)
|
||||||
|
// app.Router.Use/UseGlobal/Done(...)
|
||||||
|
app.Register(new(MyController))
|
||||||
|
}
|
||||||
|
|
||||||
|
type MyController struct {}
|
||||||
|
|
||||||
|
func (m *MyController) BeforeActivation(b mvc.BeforeActivation) {
|
||||||
|
// b.Dependencies().Add/Remove
|
||||||
|
// b.Router().Use/UseGlobal/Done // and any standard API call you already know
|
||||||
|
|
||||||
|
// 1-> Method
|
||||||
|
// 2-> Path
|
||||||
|
// 3-> The controller's function name to be parsed as handler
|
||||||
|
// 4-> Any handlers that should run before the MyCustomHandler
|
||||||
|
b.Handle("GET", "/something/{id:long}", "MyCustomHandler", anyMiddleware...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: http://localhost:8080/root
|
||||||
|
func (m *MyController) Get() string { return "Hey" }
|
||||||
|
|
||||||
|
// GET: http://localhost:8080/root/something/{id:long}
|
||||||
|
func (m *MyController) MyCustomHandler(id int64) string { return "MyCustomHandler says Hey" }
|
||||||
|
```
|
||||||
|
|
||||||
Persistence data inside your Controller struct (share data between requests)
|
Persistence data inside your Controller struct (share data between requests)
|
||||||
via `iris:"persistence"` tag right to the field or Bind using `app.Controller("/" , new(myController), theBindValue)`.
|
by defining services to the Dependencies or have a `Singleton` controller scope.
|
||||||
|
|
||||||
Models inside your Controller struct (set-ed at the Method function and rendered by the View)
|
Share the dependencies between controllers or register them on a parent MVC Application, and ability
|
||||||
via `iris:"model"` tag right to the field, i.e ```User UserModel `iris:"model" name:"user"` ``` view will recognise it as `{{.user}}`.
|
to modify dependencies per-controller on the `BeforeActivation` optional event callback inside a Controller,
|
||||||
If `name` tag is missing then it takes the field's name, in this case the `"User"`.
|
i.e `func(c *MyController) BeforeActivation(b mvc.BeforeActivation) { b.Dependencies().Add/Remove(...) }`.
|
||||||
|
|
||||||
Access to the request path and its parameters via the `Path and Params` fields.
|
Access to the `Context` as a controller's field(no manual binding is neede) i.e `Ctx iris.Context` or via a method's input argument, i.e `func(ctx iris.Context, otherArguments...)`.
|
||||||
|
|
||||||
Access to the template file that should be rendered via the `Tmpl` field.
|
Models inside your Controller struct (set-ed at the Method function and rendered by the View).
|
||||||
|
You can return models from a controller's method or set a field in the request lifecycle
|
||||||
|
and return that field to another method, in the same request lifecycle.
|
||||||
|
|
||||||
Access to the template data that should be rendered inside
|
Flow as you used to, mvc application has its own `Router` which is a type of `iris/router.Party`, the standard iris api.
|
||||||
the template file via `Data` field.
|
`Controllers` can be registered to any `Party`, including Subdomains, the Party's begin and done handlers work as expected.
|
||||||
|
|
||||||
Access to the template layout via the `Layout` field.
|
|
||||||
|
|
||||||
Access to the low-level `iris.Context` via the `Ctx` field.
|
|
||||||
|
|
||||||
Get the relative request path by using the controller's name via `RelPath()`.
|
|
||||||
|
|
||||||
Get the relative template path directory by using the controller's name via `RelTmpl()`.
|
|
||||||
|
|
||||||
Flow as you used to, `Controllers` can be registered to any `Party`,
|
|
||||||
including Subdomains, the Party's begin and done handlers work as expected.
|
|
||||||
|
|
||||||
Optional `BeginRequest(ctx)` function to perform any initialization before the method execution,
|
Optional `BeginRequest(ctx)` function to perform any initialization before the method execution,
|
||||||
useful to call middlewares or when many methods use the same collection of data.
|
useful to call middlewares or when many methods use the same collection of data.
|
||||||
|
|
||||||
Optional `EndRequest(ctx)` function to perform any finalization after any method executed.
|
Optional `EndRequest(ctx)` function to perform any finalization after any method executed.
|
||||||
|
|
||||||
Inheritance, recursively, see for example our `mvc.SessionController`, it has the `iris.Controller` as an embedded field
|
Inheritance, recursively, see for example our `mvc.SessionController`, it has the `Session *sessions.Session` and `Manager *sessions.Sessions` as embedded fields
|
||||||
and it adds its logic to its `BeginRequest`, [here](https://github.com/kataras/iris/blob/master/mvc/session_controller.go).
|
which are filled by its `BeginRequest`, [here](https://github.com/kataras/iris/blob/master/mvc/session_controller.go).
|
||||||
|
This is just an example, you could use the `mvc.Session(mySessions)` as a dependency to the MVC Application, i.e
|
||||||
|
`mvcApp.AddDependencies(mvc.Session(sessions.New(sessions.Config{Cookie: "iris_session_id"})))`.
|
||||||
|
|
||||||
Read access to the current route via the `Route` field.
|
Access to the dynamic path parameters via the controller's methods' input arguments, no binding is needed.
|
||||||
|
When you use the Iris' default syntax to parse handlers from a controller, you need to suffix the methods
|
||||||
|
with the `By` word, uppercase is a new sub path. Example:
|
||||||
|
|
||||||
Register one or more relative paths and able to get path parameters, i.e
|
If `mvc.New(app.Party("/user")).Register(new(user.Controller))`
|
||||||
|
|
||||||
If `app.Controller("/user", new(user.Controller))`
|
- `func(*Controller) Get()` - `GET:/user`.
|
||||||
|
- `func(*Controller) Post()` - `POST:/user`.
|
||||||
- `func(*Controller) Get()` - `GET:/user` , as usual.
|
|
||||||
- `func(*Controller) Post()` - `POST:/user`, as usual.
|
|
||||||
- `func(*Controller) GetLogin()` - `GET:/user/login`
|
- `func(*Controller) GetLogin()` - `GET:/user/login`
|
||||||
- `func(*Controller) PostLogin()` - `POST:/user/login`
|
- `func(*Controller) PostLogin()` - `POST:/user/login`
|
||||||
- `func(*Controller) GetProfileFollowers()` - `GET:/user/profile/followers`
|
- `func(*Controller) GetProfileFollowers()` - `GET:/user/profile/followers`
|
||||||
|
@ -62,11 +96,11 @@ If `app.Controller("/user", new(user.Controller))`
|
||||||
- `func(*Controller) GetBy(id int64)` - `GET:/user/{param:long}`
|
- `func(*Controller) GetBy(id int64)` - `GET:/user/{param:long}`
|
||||||
- `func(*Controller) PostBy(id int64)` - `POST:/user/{param:long}`
|
- `func(*Controller) PostBy(id int64)` - `POST:/user/{param:long}`
|
||||||
|
|
||||||
If `app.Controller("/profile", new(profile.Controller))`
|
If `mvc.New(app.Party("/profile")).Register(new(profile.Controller))`
|
||||||
|
|
||||||
- `func(*Controller) GetBy(username string)` - `GET:/profile/{param:string}`
|
- `func(*Controller) GetBy(username string)` - `GET:/profile/{param:string}`
|
||||||
|
|
||||||
If `app.Controller("/assets", new(file.Controller))`
|
If `mvc.New(app.Party("/assets")).Register(new(file.Controller))`
|
||||||
|
|
||||||
- `func(*Controller) GetByWildard(path string)` - `GET:/assets/{param:path}`
|
- `func(*Controller) GetByWildard(path string)` - `GET:/assets/{param:path}`
|
||||||
|
|
||||||
|
@ -91,7 +125,7 @@ func(c *ExampleController) Get() string |
|
||||||
mvc.Result or (mvc.Result, error)
|
mvc.Result or (mvc.Result, error)
|
||||||
```
|
```
|
||||||
|
|
||||||
where [mvc.Result](https://github.com/kataras/iris/blob/master/mvc/method_result.go) is an interface which contains only that function: `Dispatch(ctx iris.Context)`.
|
where [mvc.Result](https://github.com/kataras/iris/blob/master/mvc/func_result.go) is an interface which contains only that function: `Dispatch(ctx iris.Context)`.
|
||||||
|
|
||||||
## Using Iris MVC for code reuse
|
## Using Iris MVC for code reuse
|
||||||
|
|
||||||
|
|
|
@ -25,25 +25,6 @@ type UsersController struct {
|
||||||
Service services.UserService
|
Service services.UserService
|
||||||
}
|
}
|
||||||
|
|
||||||
// This could be possible but we should not call handlers inside the `BeginRequest`.
|
|
||||||
// Because `BeginRequest` was introduced to set common, shared variables between all method handlers
|
|
||||||
// before their execution.
|
|
||||||
// We will add this middleware from our `app.Controller` call.
|
|
||||||
//
|
|
||||||
// var authMiddleware = basicauth.New(basicauth.Config{
|
|
||||||
// Users: map[string]string{
|
|
||||||
// "admin": "password",
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// func (c *UsersController) BeginRequest(ctx iris.Context) {
|
|
||||||
// c.C.BeginRequest(ctx)
|
|
||||||
//
|
|
||||||
// if !ctx.Proceed(authMiddleware) {
|
|
||||||
// ctx.StopExecution()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Get returns list of the users.
|
// Get returns list of the users.
|
||||||
// Demo:
|
// Demo:
|
||||||
// curl -i -u admin:password http://localhost:8080/users
|
// curl -i -u admin:password http://localhost:8080/users
|
||||||
|
|
|
@ -17,7 +17,7 @@ type VisitController struct {
|
||||||
// its initialization happens by the dependency function that we've added to the `visitApp`.
|
// its initialization happens by the dependency function that we've added to the `visitApp`.
|
||||||
Session *sessions.Session
|
Session *sessions.Session
|
||||||
|
|
||||||
// A time.time which is binded from the `app.Controller`,
|
// A time.time which is binded from the MVC,
|
||||||
// order of binded fields doesn't matter.
|
// order of binded fields doesn't matter.
|
||||||
StartTime time.Time
|
StartTime time.Time
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,8 +267,7 @@ type Context interface {
|
||||||
// Although `BeginRequest` should NOT be used to call other handlers,
|
// Although `BeginRequest` should NOT be used to call other handlers,
|
||||||
// the `BeginRequest` has been introduced to be able to set
|
// the `BeginRequest` has been introduced to be able to set
|
||||||
// common data to all method handlers before their execution.
|
// common data to all method handlers before their execution.
|
||||||
// Controllers can accept middleware(s) from the `app.Controller`
|
// Controllers can accept middleware(s) from the MVC's Application's Router as normally.
|
||||||
// function.
|
|
||||||
//
|
//
|
||||||
// That said let's see an example of `ctx.Proceed`:
|
// That said let's see an example of `ctx.Proceed`:
|
||||||
//
|
//
|
||||||
|
@ -279,7 +278,6 @@ type Context interface {
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
// func (c *UsersController) BeginRequest(ctx iris.Context) {
|
// func (c *UsersController) BeginRequest(ctx iris.Context) {
|
||||||
// c.C.BeginRequest(ctx) // call the parent's base controller BeginRequest first.
|
|
||||||
// if !ctx.Proceed(authMiddleware) {
|
// if !ctx.Proceed(authMiddleware) {
|
||||||
// ctx.StopExecution()
|
// ctx.StopExecution()
|
||||||
// }
|
// }
|
||||||
|
@ -1055,8 +1053,7 @@ func (ctx *context) HandlerIndex(n int) (currentIndex int) {
|
||||||
// Although `BeginRequest` should NOT be used to call other handlers,
|
// Although `BeginRequest` should NOT be used to call other handlers,
|
||||||
// the `BeginRequest` has been introduced to be able to set
|
// the `BeginRequest` has been introduced to be able to set
|
||||||
// common data to all method handlers before their execution.
|
// common data to all method handlers before their execution.
|
||||||
// Controllers can accept middleware(s) from the `app.Controller`
|
// Controllers can accept middleware(s) from the MVC's Application's Router as normally.
|
||||||
// function.
|
|
||||||
//
|
//
|
||||||
// That said let's see an example of `ctx.Proceed`:
|
// That said let's see an example of `ctx.Proceed`:
|
||||||
//
|
//
|
||||||
|
@ -1067,7 +1064,6 @@ func (ctx *context) HandlerIndex(n int) (currentIndex int) {
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
// func (c *UsersController) BeginRequest(ctx iris.Context) {
|
// func (c *UsersController) BeginRequest(ctx iris.Context) {
|
||||||
// c.C.BeginRequest(ctx) // call the parent's base controller BeginRequest first.
|
|
||||||
// if !ctx.Proceed(authMiddleware) {
|
// if !ctx.Proceed(authMiddleware) {
|
||||||
// ctx.StopExecution()
|
// ctx.StopExecution()
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -201,7 +201,6 @@ func (api *APIBuilder) HandleMany(methodOrMulti string, relativePathorMulti stri
|
||||||
// at least slash
|
// at least slash
|
||||||
// a space
|
// a space
|
||||||
// at least one other slash for the next path
|
// at least one other slash for the next path
|
||||||
// app.Controller("/user /user{id}", new(UserController))
|
|
||||||
paths := splitPath(relativePathorMulti)
|
paths := splitPath(relativePathorMulti)
|
||||||
methods := splitMethod(methodOrMulti)
|
methods := splitMethod(methodOrMulti)
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
|
|
636
doc.go
636
doc.go
|
@ -683,365 +683,6 @@ Example code:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MVC - Model View Controller
|
|
||||||
|
|
||||||
Iris has first-class support for the MVC pattern, you'll not find
|
|
||||||
these stuff anywhere else in the Go world.
|
|
||||||
|
|
||||||
Example Code:
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kataras/iris"
|
|
||||||
|
|
||||||
"github.com/kataras/iris/middleware/logger"
|
|
||||||
"github.com/kataras/iris/middleware/recover"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This example is equivalent to the
|
|
||||||
// https://github.com/kataras/iris/blob/master/_examples/hello-world/main.go
|
|
||||||
//
|
|
||||||
// It seems that additional code you
|
|
||||||
// have to write doesn't worth it
|
|
||||||
// but remember that, this example
|
|
||||||
// does not make use of iris mvc features like
|
|
||||||
// the Model, Persistence or the View engine neither the Session,
|
|
||||||
// it's very simple for learning purposes,
|
|
||||||
// probably you'll never use such
|
|
||||||
// as simple controller anywhere in your app.
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
app := iris.New()
|
|
||||||
// Optionally, add two built'n handlers
|
|
||||||
// that can recover from any http-relative panics
|
|
||||||
// and log the requests to the terminal.
|
|
||||||
app.Use(recover.New())
|
|
||||||
app.Use(logger.New())
|
|
||||||
|
|
||||||
app.Controller("/", new(IndexController))
|
|
||||||
app.Controller("/ping", new(PingController))
|
|
||||||
app.Controller("/hello", new(HelloController))
|
|
||||||
|
|
||||||
// http://localhost:8080
|
|
||||||
// http://localhost:8080/ping
|
|
||||||
// http://localhost:8080/hello
|
|
||||||
app.Run(iris.Addr(":8080"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IndexController serves the "/".
|
|
||||||
type IndexController struct {
|
|
||||||
// if you build with go1.8 you have to use the mvc package, `mvc.Controller` instead.
|
|
||||||
iris.Controller
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get serves
|
|
||||||
// Method: GET
|
|
||||||
// Resource: http://localhost:8080/
|
|
||||||
func (c *IndexController) Get() {
|
|
||||||
c.Ctx.HTML("<b>Welcome!</b>")
|
|
||||||
}
|
|
||||||
|
|
||||||
// PingController serves the "/ping".
|
|
||||||
type PingController struct {
|
|
||||||
iris.Controller
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get serves
|
|
||||||
// Method: GET
|
|
||||||
// Resource: http://localhost:8080/ping
|
|
||||||
func (c *PingController) Get() {
|
|
||||||
c.Ctx.WriteString("pong")
|
|
||||||
}
|
|
||||||
|
|
||||||
// HelloController serves the "/hello".
|
|
||||||
type HelloController struct {
|
|
||||||
iris.Controller
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get serves
|
|
||||||
// Method: GET
|
|
||||||
// Resource: http://localhost:8080/hello
|
|
||||||
func (c *HelloController) Get() {
|
|
||||||
c.Ctx.JSON(iris.Map{"message": "Hello iris web framework."})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can use more than one, the factory will make sure
|
|
||||||
// that the correct http methods are being registered for each route
|
|
||||||
// for this controller, uncomment these if you want:
|
|
||||||
|
|
||||||
// func (c *HelloController) Post() {}
|
|
||||||
// func (c *HelloController) Put() {}
|
|
||||||
// func (c *HelloController) Delete() {}
|
|
||||||
// func (c *HelloController) Connect() {}
|
|
||||||
// func (c *HelloController) Head() {}
|
|
||||||
// func (c *HelloController) Patch() {}
|
|
||||||
// func (c *HelloController) Options() {}
|
|
||||||
// func (c *HelloController) Trace() {}
|
|
||||||
// or All() or Any() to catch all http methods.
|
|
||||||
|
|
||||||
|
|
||||||
Iris web framework supports Request data, Models, Persistence Data and Binding
|
|
||||||
with the fastest possible execution.
|
|
||||||
|
|
||||||
Characteristics:
|
|
||||||
|
|
||||||
All HTTP Methods are supported, for example if want to serve `GET`
|
|
||||||
then the controller should have a function named `Get()`,
|
|
||||||
you can define more than one method function to serve in the same Controller struct.
|
|
||||||
|
|
||||||
Persistence data inside your Controller struct (share data between requests)
|
|
||||||
via `iris:"persistence"` tag right to the field or Bind using `app.Controller("/" , new(myController), theBindValue)`.
|
|
||||||
|
|
||||||
Models inside your Controller struct (set-ed at the Method function and rendered by the View)
|
|
||||||
via `iris:"model"` tag right to the field, i.e User UserModel `iris:"model" name:"user"`
|
|
||||||
view will recognise it as `{{.user}}`.
|
|
||||||
If `name` tag is missing then it takes the field's name, in this case the `"User"`.
|
|
||||||
|
|
||||||
Access to the request path and its parameters via the `Path and Params` fields.
|
|
||||||
|
|
||||||
Access to the template file that should be rendered via the `Tmpl` field.
|
|
||||||
|
|
||||||
Access to the template data that should be rendered inside
|
|
||||||
the template file via `Data` field.
|
|
||||||
|
|
||||||
Access to the template layout via the `Layout` field.
|
|
||||||
|
|
||||||
Access to the low-level `iris.Context` via the `Ctx` field.
|
|
||||||
|
|
||||||
Get the relative request path by using the controller's name via `RelPath()`.
|
|
||||||
|
|
||||||
Get the relative template path directory by using the controller's name via `RelTmpl()`.
|
|
||||||
|
|
||||||
Flow as you used to, `Controllers` can be registered to any `Party`,
|
|
||||||
including Subdomains, the Party's begin and done handlers work as expected.
|
|
||||||
|
|
||||||
Optional `BeginRequest(ctx)` function to perform any initialization before the method execution,
|
|
||||||
useful to call middlewares or when many methods use the same collection of data.
|
|
||||||
|
|
||||||
Optional `EndRequest(ctx)` function to perform any finalization after any method executed.
|
|
||||||
|
|
||||||
Inheritance, recursively, see for example our `mvc.SessionController/iris.SessionController`, it has the `mvc.Controller/iris.Controller` as an embedded field
|
|
||||||
and it adds its logic to its `BeginRequest`. Source file: https://github.com/kataras/iris/blob/master/mvc/session_controller.go.
|
|
||||||
|
|
||||||
Read access to the current route via the `Route` field.
|
|
||||||
|
|
||||||
Support for more than one input arguments (map to dynamic request path parameters).
|
|
||||||
|
|
||||||
Register one or more relative paths and able to get path parameters, i.e
|
|
||||||
|
|
||||||
If `app.Controller("/user", new(user.Controller))`
|
|
||||||
|
|
||||||
- `func(*Controller) Get()` - `GET:/user` , as usual.
|
|
||||||
- `func(*Controller) Post()` - `POST:/user`, as usual.
|
|
||||||
- `func(*Controller) GetLogin()` - `GET:/user/login`
|
|
||||||
- `func(*Controller) PostLogin()` - `POST:/user/login`
|
|
||||||
- `func(*Controller) GetProfileFollowers()` - `GET:/user/profile/followers`
|
|
||||||
- `func(*Controller) PostProfileFollowers()` - `POST:/user/profile/followers`
|
|
||||||
- `func(*Controller) GetBy(id int64)` - `GET:/user/{param:long}`
|
|
||||||
- `func(*Controller) PostBy(id int64)` - `POST:/user/{param:long}`
|
|
||||||
If `app.Controller("/profile", new(profile.Controller))`
|
|
||||||
|
|
||||||
- `func(*Controller) GetBy(username string)` - `GET:/profile/{param:string}`
|
|
||||||
|
|
||||||
If `app.Controller("/assets", new(file.Controller))`
|
|
||||||
|
|
||||||
- `func(*Controller) GetByWildard(path string)` - `GET:/assets/{param:path}`
|
|
||||||
|
|
||||||
If `app.Controller("/equality", new(profile.Equality))`
|
|
||||||
|
|
||||||
- `func(*Controller) GetBy(is bool)` - `GET:/equality/{param:boolean}`
|
|
||||||
- `func(*Controller) GetByOtherBy(is bool, otherID int64)` - `GET:/equality/{paramfirst:boolean}/other/{paramsecond:long}`
|
|
||||||
|
|
||||||
Supported types for method functions receivers: int, int64, bool and string.
|
|
||||||
|
|
||||||
Response via output arguments, optionally, i.e
|
|
||||||
|
|
||||||
func(c *ExampleController) Get() string |
|
|
||||||
(string, string) |
|
|
||||||
(string, int) |
|
|
||||||
(string, error) |
|
|
||||||
int |
|
|
||||||
(int, string) |
|
|
||||||
(any, int) |
|
|
||||||
error |
|
|
||||||
(int, error) |
|
|
||||||
(customStruct, error) |
|
|
||||||
(any, error) |
|
|
||||||
bool |
|
|
||||||
(any, bool)
|
|
||||||
customStruct |
|
|
||||||
(customStruct, int) |
|
|
||||||
(customStruct, string) |
|
|
||||||
`Result` or (`Result`, error)
|
|
||||||
|
|
||||||
Where `any` means everything, from custom structs to standard language's types-.
|
|
||||||
`Result` is an interface which contains only that function: Dispatch(ctx iris.Context)
|
|
||||||
and Get where HTTP Method function(Post, Put, Delete...).
|
|
||||||
|
|
||||||
|
|
||||||
Iris MVC Method Result
|
|
||||||
|
|
||||||
Iris has a very powerful and blazing fast MVC support, you can return any value of any type from a method function
|
|
||||||
and it will be sent to the client as expected.
|
|
||||||
|
|
||||||
* if `string` then it's the body.
|
|
||||||
* if `string` is the second output argument then it's the content type.
|
|
||||||
* if `int` then it's the status code.
|
|
||||||
* if `bool` is false then it throws 404 not found http error by skipping everything else.
|
|
||||||
* if `error` and not nil then (any type) response will be omitted and error's text with a 400 bad request will be rendered instead.
|
|
||||||
* if `(int, error)` and error is not nil then the response result will be the error's text with the status code as `int`.
|
|
||||||
* if `custom struct` or `interface{}` or `slice` or `map` then it will be rendered as json, unless a `string` content type is following.
|
|
||||||
* if `mvc.Result` then it executes its `Dispatch` function, so good design patters can be used to split the model's logic where needed.
|
|
||||||
|
|
||||||
|
|
||||||
The example below is not intended to be used in production but it's a good showcase of some of the return types we saw before;
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kataras/iris"
|
|
||||||
"github.com/kataras/iris/middleware/basicauth"
|
|
||||||
"github.com/kataras/iris/mvc"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Movie is our sample data structure.
|
|
||||||
type Movie struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Year int `json:"year"`
|
|
||||||
Genre string `json:"genre"`
|
|
||||||
Poster string `json:"poster"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// movies contains our imaginary data source.
|
|
||||||
var movies = []Movie{
|
|
||||||
{
|
|
||||||
Name: "Casablanca",
|
|
||||||
Year: 1942,
|
|
||||||
Genre: "Romance",
|
|
||||||
Poster: "https://iris-go.com/images/examples/mvc-movies/1.jpg",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Gone with the Wind",
|
|
||||||
Year: 1939,
|
|
||||||
Genre: "Romance",
|
|
||||||
Poster: "https://iris-go.com/images/examples/mvc-movies/2.jpg",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Citizen Kane",
|
|
||||||
Year: 1941,
|
|
||||||
Genre: "Mystery",
|
|
||||||
Poster: "https://iris-go.com/images/examples/mvc-movies/3.jpg",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "The Wizard of Oz",
|
|
||||||
Year: 1939,
|
|
||||||
Genre: "Fantasy",
|
|
||||||
Poster: "https://iris-go.com/images/examples/mvc-movies/4.jpg",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var basicAuth = basicauth.New(basicauth.Config{
|
|
||||||
Users: map[string]string{
|
|
||||||
"admin": "password",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
app := iris.New()
|
|
||||||
|
|
||||||
app.Use(basicAuth)
|
|
||||||
|
|
||||||
app.Controller("/movies", new(MoviesController))
|
|
||||||
|
|
||||||
app.Run(iris.Addr(":8080"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// MoviesController is our /movies controller.
|
|
||||||
type MoviesController struct {
|
|
||||||
// if you build with go1.8 you have to use the mvc package always,
|
|
||||||
// otherwise
|
|
||||||
// you can, optionally
|
|
||||||
// use the type alias `iris.C`,
|
|
||||||
// same for
|
|
||||||
// context.Context -> iris.Context,
|
|
||||||
// mvc.Result -> iris.Result,
|
|
||||||
// mvc.Response -> iris.Response,
|
|
||||||
// mvc.View -> iris.View
|
|
||||||
mvc.C
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns list of the movies
|
|
||||||
// Demo:
|
|
||||||
// curl -i http://localhost:8080/movies
|
|
||||||
func (c *MoviesController) Get() []Movie {
|
|
||||||
return movies
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBy returns a movie
|
|
||||||
// Demo:
|
|
||||||
// curl -i http://localhost:8080/movies/1
|
|
||||||
func (c *MoviesController) GetBy(id int) Movie {
|
|
||||||
return movies[id]
|
|
||||||
}
|
|
||||||
|
|
||||||
// PutBy updates a movie
|
|
||||||
// Demo:
|
|
||||||
// curl -i -X PUT -F "genre=Thriller" -F "poster=@/Users/kataras/Downloads/out.gif" http://localhost:8080/movies/1
|
|
||||||
func (c *MoviesController) PutBy(id int) Movie {
|
|
||||||
// get the movie
|
|
||||||
m := movies[id]
|
|
||||||
|
|
||||||
// get the request data for poster and genre
|
|
||||||
file, info, err := c.Ctx.FormFile("poster")
|
|
||||||
if err != nil {
|
|
||||||
c.Ctx.StatusCode(iris.StatusInternalServerError)
|
|
||||||
return Movie{}
|
|
||||||
}
|
|
||||||
file.Close() // we don't need the file
|
|
||||||
poster := info.Filename // imagine that as the url of the uploaded file...
|
|
||||||
genre := c.Ctx.FormValue("genre")
|
|
||||||
|
|
||||||
// update the poster
|
|
||||||
m.Poster = poster
|
|
||||||
m.Genre = genre
|
|
||||||
movies[id] = m
|
|
||||||
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteBy deletes a movie
|
|
||||||
// Demo:
|
|
||||||
// curl -i -X DELETE -u admin:password http://localhost:8080/movies/1
|
|
||||||
func (c *MoviesController) DeleteBy(id int) iris.Map {
|
|
||||||
// delete the entry from the movies slice
|
|
||||||
deleted := movies[id].Name
|
|
||||||
movies = append(movies[:id], movies[id+1:]...)
|
|
||||||
// and return the deleted movie's name
|
|
||||||
return iris.Map{"deleted": deleted}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Another good example with a typical folder structure,
|
|
||||||
that many developers are used to work, can be found at:
|
|
||||||
https://github.com/kataras/iris/tree/master/_examples/mvc/overview.
|
|
||||||
|
|
||||||
|
|
||||||
Using Iris MVC for code reuse
|
|
||||||
|
|
||||||
By creating components that are independent of one another,
|
|
||||||
developers are able to reuse components quickly and easily in other applications.
|
|
||||||
The same (or similar) view for one application can be refactored for another application with
|
|
||||||
different data because the view is simply handling how the data is being displayed to the user.
|
|
||||||
|
|
||||||
If you're new to back-end web development read about the MVC architectural pattern first,
|
|
||||||
a good start is that wikipedia article: https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller.
|
|
||||||
|
|
||||||
Follow the examples at: https://github.com/kataras/iris/tree/master/_examples/#mvc
|
|
||||||
|
|
||||||
|
|
||||||
Parameterized Path
|
Parameterized Path
|
||||||
|
|
||||||
At the previous example,
|
At the previous example,
|
||||||
|
@ -1838,6 +1479,283 @@ Running the example:
|
||||||
$ start http://localhost:8080
|
$ start http://localhost:8080
|
||||||
|
|
||||||
|
|
||||||
|
MVC - Model View Controller
|
||||||
|
|
||||||
|
Iris has first-class support for the MVC pattern, you'll not find
|
||||||
|
these stuff anywhere else in the Go world.
|
||||||
|
|
||||||
|
Example Code:
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kataras/iris"
|
||||||
|
"github.com/kataras/iris/mvc"
|
||||||
|
|
||||||
|
"github.com/kataras/iris/middleware/logger"
|
||||||
|
"github.com/kataras/iris/middleware/recover"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := iris.New()
|
||||||
|
// Optionally, add two built'n handlers
|
||||||
|
// that can recover from any http-relative panics
|
||||||
|
// and log the requests to the terminal.
|
||||||
|
app.Use(recover.New())
|
||||||
|
app.Use(logger.New())
|
||||||
|
|
||||||
|
// Register a controller based on the root Router, "/".
|
||||||
|
mvc.New(app).Register(new(ExampleController))
|
||||||
|
|
||||||
|
// http://localhost:8080
|
||||||
|
// http://localhost:8080/ping
|
||||||
|
// http://localhost:8080/hello
|
||||||
|
// http://localhost:8080/custom_path
|
||||||
|
app.Run(iris.Addr(":8080"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleController serves the "/", "/ping" and "/hello".
|
||||||
|
type ExampleController struct{}
|
||||||
|
|
||||||
|
// Get serves
|
||||||
|
// Method: GET
|
||||||
|
// Resource: http://localhost:8080
|
||||||
|
func (c *ExampleController) Get() mvc.Result {
|
||||||
|
return mvc.Response{
|
||||||
|
ContentType: "text/html",
|
||||||
|
Text: "<h1>Welcome</h1>",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPing serves
|
||||||
|
// Method: GET
|
||||||
|
// Resource: http://localhost:8080/ping
|
||||||
|
func (c *ExampleController) GetPing() string {
|
||||||
|
return "pong"
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHello serves
|
||||||
|
// Method: GET
|
||||||
|
// Resource: http://localhost:8080/hello
|
||||||
|
func (c *ExampleController) GetHello() interface{} {
|
||||||
|
return map[string]string{"message": "Hello Iris!"}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// GetUserBy serves
|
||||||
|
// Method: GET
|
||||||
|
// Resource: http://localhost:8080/user/{username:string}
|
||||||
|
// By is a reserved "keyword" to tell the framework that you're going to
|
||||||
|
// bind path parameters in the function's input arguments, and it also
|
||||||
|
// helps to have "Get" and "GetBy" in the same controller.
|
||||||
|
//
|
||||||
|
// func (c *ExampleController) GetUserBy(username string) mvc.Result {
|
||||||
|
// return mvc.View{
|
||||||
|
// Name: "user/username.html",
|
||||||
|
// Data: username,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
Can use more than one, the factory will make sure
|
||||||
|
that the correct http methods are being registered for each route
|
||||||
|
for this controller, uncomment these if you want:
|
||||||
|
|
||||||
|
func (c *ExampleController) Post() {}
|
||||||
|
func (c *ExampleController) Put() {}
|
||||||
|
func (c *ExampleController) Delete() {}
|
||||||
|
func (c *ExampleController) Connect() {}
|
||||||
|
func (c *ExampleController) Head() {}
|
||||||
|
func (c *ExampleController) Patch() {}
|
||||||
|
func (c *ExampleController) Options() {}
|
||||||
|
func (c *ExampleController) Trace() {}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (c *ExampleController) All() {}
|
||||||
|
// OR
|
||||||
|
func (c *ExampleController) Any() {}
|
||||||
|
|
||||||
|
func (c *ExampleController) BeforeActivation(b mvc.BeforeActivation) {
|
||||||
|
// 1 -> the HTTP Method
|
||||||
|
// 2 -> the route's path
|
||||||
|
// 3 -> this controller's method name that should be handler for that route.
|
||||||
|
b.Handle("GET", "/mypath/{param}", "DoIt", optionalMiddlewareHere...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// After activation, all dependencies are set-ed - so read only access on them
|
||||||
|
// but still possible to add custom controller or simple standard handlers.
|
||||||
|
func (c *ExampleController) AfterActivation(a mvc.AfterActivation) {}
|
||||||
|
|
||||||
|
|
||||||
|
Iris web framework supports Request data, Models, Persistence Data and Binding
|
||||||
|
with the fastest possible execution.
|
||||||
|
|
||||||
|
Characteristics:
|
||||||
|
|
||||||
|
All HTTP Methods are supported, for example if want to serve `GET`
|
||||||
|
then the controller should have a function named `Get()`,
|
||||||
|
you can define more than one method function to serve in the same Controller.
|
||||||
|
|
||||||
|
Register custom controller's struct's methods as handlers with custom paths(even with regex parametermized path)
|
||||||
|
via the `BeforeActivation` custom event callback, per-controller. Example:
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kataras/iris"
|
||||||
|
"github.com/kataras/iris/mvc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := iris.New()
|
||||||
|
mvc.Configure(app.Party("/root"), myMVC)
|
||||||
|
app.Run(iris.Addr(":8080"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func myMVC(app *mvc.Application) {
|
||||||
|
// app.AddDependencies(...)
|
||||||
|
// app.Router.Use/UseGlobal/Done(...)
|
||||||
|
app.Register(new(MyController))
|
||||||
|
}
|
||||||
|
|
||||||
|
type MyController struct {}
|
||||||
|
|
||||||
|
func (m *MyController) BeforeActivation(b mvc.BeforeActivation) {
|
||||||
|
// b.Dependencies().Add/Remove
|
||||||
|
// b.Router().Use/UseGlobal/Done // and any standard API call you already know
|
||||||
|
|
||||||
|
// 1-> Method
|
||||||
|
// 2-> Path
|
||||||
|
// 3-> The controller's function name to be parsed as handler
|
||||||
|
// 4-> Any handlers that should run before the MyCustomHandler
|
||||||
|
b.Handle("GET", "/something/{id:long}", "MyCustomHandler", anyMiddleware...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: http://localhost:8080/root
|
||||||
|
func (m *MyController) Get() string { return "Hey" }
|
||||||
|
|
||||||
|
// GET: http://localhost:8080/root/something/{id:long}
|
||||||
|
func (m *MyController) MyCustomHandler(id int64) string { return "MyCustomHandler says Hey" }
|
||||||
|
|
||||||
|
|
||||||
|
Persistence data inside your Controller struct (share data between requests)
|
||||||
|
by defining services to the Dependencies or have a `Singleton` controller scope.
|
||||||
|
|
||||||
|
Share the dependencies between controllers or register them on a parent MVC Application, and ability
|
||||||
|
to modify dependencies per-controller on the `BeforeActivation` optional event callback inside a Controller,
|
||||||
|
i.e
|
||||||
|
|
||||||
|
func(c *MyController) BeforeActivation(b mvc.BeforeActivation) { b.Dependencies().Add/Remove(...) }
|
||||||
|
|
||||||
|
Access to the `Context` as a controller's field(no manual binding is neede) i.e `Ctx iris.Context` or via a method's input argument,
|
||||||
|
i.e
|
||||||
|
func(ctx iris.Context, otherArguments...)
|
||||||
|
|
||||||
|
Models inside your Controller struct (set-ed at the Method function and rendered by the View).
|
||||||
|
You can return models from a controller's method or set a field in the request lifecycle
|
||||||
|
and return that field to another method, in the same request lifecycle.
|
||||||
|
|
||||||
|
Flow as you used to, mvc application has its own `Router` which is a type of `iris/router.Party`, the standard iris api.
|
||||||
|
`Controllers` can be registered to any `Party`, including Subdomains, the Party's begin and done handlers work as expected.
|
||||||
|
|
||||||
|
Optional `BeginRequest(ctx)` function to perform any initialization before the method execution,
|
||||||
|
useful to call middlewares or when many methods use the same collection of data.
|
||||||
|
|
||||||
|
Optional `EndRequest(ctx)` function to perform any finalization after any method executed.
|
||||||
|
|
||||||
|
Session dependency via `mvc.Session(mySessions)` to the MVC Application, i.e
|
||||||
|
|
||||||
|
mvcApp.AddDependencies(mvc.Session(sessions.New(sessions.Config{Cookie: "iris_session_id"})))
|
||||||
|
|
||||||
|
Inheritance, recursively.
|
||||||
|
|
||||||
|
Access to the dynamic path parameters via the controller's methods' input arguments, no binding is needed.
|
||||||
|
When you use the Iris' default syntax to parse handlers from a controller, you need to suffix the methods
|
||||||
|
with the `By` word, uppercase is a new sub path. Example:
|
||||||
|
|
||||||
|
Register one or more relative paths and able to get path parameters, i.e
|
||||||
|
|
||||||
|
If `mvc.New(app.Party("/user")).Register(new(user.Controller))`
|
||||||
|
|
||||||
|
- `func(*Controller) Get()` - `GET:/user` , as usual.
|
||||||
|
- `func(*Controller) Post()` - `POST:/user`, as usual.
|
||||||
|
- `func(*Controller) GetLogin()` - `GET:/user/login`
|
||||||
|
- `func(*Controller) PostLogin()` - `POST:/user/login`
|
||||||
|
- `func(*Controller) GetProfileFollowers()` - `GET:/user/profile/followers`
|
||||||
|
- `func(*Controller) PostProfileFollowers()` - `POST:/user/profile/followers`
|
||||||
|
- `func(*Controller) GetBy(id int64)` - `GET:/user/{param:long}`
|
||||||
|
- `func(*Controller) PostBy(id int64)` - `POST:/user/{param:long}`
|
||||||
|
|
||||||
|
If `mvc.New(app.Party("/profile")).Register(new(profile.Controller))`
|
||||||
|
|
||||||
|
- `func(*Controller) GetBy(username string)` - `GET:/profile/{param:string}`
|
||||||
|
|
||||||
|
If `mvc.New(app.Party("/assets")).Register(new(file.Controller))`
|
||||||
|
|
||||||
|
- `func(*Controller) GetByWildard(path string)` - `GET:/assets/{param:path}`
|
||||||
|
|
||||||
|
If `mvc.New(app.Party("/equality")).Register(new(profile.Equality))`
|
||||||
|
|
||||||
|
- `func(*Controller) GetBy(is bool)` - `GET:/equality/{param:boolean}`
|
||||||
|
- `func(*Controller) GetByOtherBy(is bool, otherID int64)` - `GET:/equality/{paramfirst:boolean}/other/{paramsecond:long}`
|
||||||
|
|
||||||
|
Supported types for method functions receivers: int, int64, bool and string.
|
||||||
|
|
||||||
|
Response via output arguments, optionally, i.e
|
||||||
|
|
||||||
|
func(c *ExampleController) Get() string |
|
||||||
|
(string, string) |
|
||||||
|
(string, int) |
|
||||||
|
(string, error) |
|
||||||
|
int |
|
||||||
|
(int, string) |
|
||||||
|
(any, int) |
|
||||||
|
error |
|
||||||
|
(int, error) |
|
||||||
|
(customStruct, error) |
|
||||||
|
(any, error) |
|
||||||
|
bool |
|
||||||
|
(any, bool)
|
||||||
|
customStruct |
|
||||||
|
(customStruct, int) |
|
||||||
|
(customStruct, string) |
|
||||||
|
`Result` or (`Result`, error)
|
||||||
|
|
||||||
|
Where `any` means everything, from custom structs to standard language's types-.
|
||||||
|
`Result` is an interface which contains only that function: Dispatch(ctx iris.Context)
|
||||||
|
and Get where HTTP Method function(Post, Put, Delete...).
|
||||||
|
|
||||||
|
|
||||||
|
Iris MVC Method Result
|
||||||
|
|
||||||
|
Iris has a very powerful and blazing fast MVC support, you can return any value of any type from a method function
|
||||||
|
and it will be sent to the client as expected.
|
||||||
|
|
||||||
|
* if `string` then it's the body.
|
||||||
|
* if `string` is the second output argument then it's the content type.
|
||||||
|
* if `int` then it's the status code.
|
||||||
|
* if `bool` is false then it throws 404 not found http error by skipping everything else.
|
||||||
|
* if `error` and not nil then (any type) response will be omitted and error's text with a 400 bad request will be rendered instead.
|
||||||
|
* if `(int, error)` and error is not nil then the response result will be the error's text with the status code as `int`.
|
||||||
|
* if `custom struct` or `interface{}` or `slice` or `map` then it will be rendered as json, unless a `string` content type is following.
|
||||||
|
* if `mvc.Result` then it executes its `Dispatch` function, so good design patters can be used to split the model's logic where needed.
|
||||||
|
|
||||||
|
Examples with good patterns to follow but not intend to be used in production of course can be found at:
|
||||||
|
https://github.com/kataras/iris/tree/master/_examples/#mvc.
|
||||||
|
|
||||||
|
|
||||||
|
Using Iris MVC for code reuse
|
||||||
|
|
||||||
|
By creating components that are independent of one another,
|
||||||
|
developers are able to reuse components quickly and easily in other applications.
|
||||||
|
The same (or similar) view for one application can be refactored for another application with
|
||||||
|
different data because the view is simply handling how the data is being displayed to the user.
|
||||||
|
|
||||||
|
If you're new to back-end web development read about the MVC architectural pattern first,
|
||||||
|
a good start is that wikipedia article: https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
That's the basics
|
That's the basics
|
||||||
|
|
||||||
But you should have a basic idea of the framework by now, we just scratched the surface.
|
But you should have a basic idea of the framework by now, we just scratched the surface.
|
||||||
|
|
|
@ -21,7 +21,7 @@ type SessionController struct {
|
||||||
// BeforeActivation called, once per application lifecycle NOT request,
|
// BeforeActivation called, once per application lifecycle NOT request,
|
||||||
// every single time the dev registers a specific SessionController-based controller.
|
// every single time the dev registers a specific SessionController-based controller.
|
||||||
// It makes sure that its "Manager" field is filled
|
// It makes sure that its "Manager" field is filled
|
||||||
// even if the caller didn't provide any sessions manager via the `app.Controller` function.
|
// even if the caller didn't provide any sessions manager via the MVC's Application's `Register` function.
|
||||||
func (s *SessionController) BeforeActivation(b BeforeActivation) {
|
func (s *SessionController) BeforeActivation(b BeforeActivation) {
|
||||||
if didntBindManually := b.Dependencies().AddOnce(defaultSessionManager); didntBindManually {
|
if didntBindManually := b.Dependencies().AddOnce(defaultSessionManager); didntBindManually {
|
||||||
b.Router().GetReporter().Add(
|
b.Router().GetReporter().Add(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user