diff --git a/README.md b/README.md index af3ab603..a0dfa3a3 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ Help this project to continue deliver awesome and unique features with the highe * [Installation](#-installation) * [Latest changes](https://github.com/kataras/iris/blob/master/HISTORY.md#we-27-september-2017--v843) * [Learn](#-learn) + * [Structuring](_examples/#structuring) * [HTTP Listening](_examples/#http-listening) * [Configuration](_examples/#configuration) * [Routing, Grouping, Dynamic Path Parameters, "Macros" and Custom Context](_examples/#routing-grouping-dynamic-path-parameters-macros-and-custom-context) diff --git a/_examples/README.md b/_examples/README.md index bf637d17..e0aa242e 100644 --- a/_examples/README.md +++ b/_examples/README.md @@ -14,7 +14,16 @@ It doesn't always contain the "best ways" but it does cover each important featu - [Tutorial: URL Shortener using BoltDB](https://medium.com/@kataras/a-url-shortener-service-using-go-iris-and-bolt-4182f0b00ae7) - [Tutorial: How to turn your Android Device into a fully featured Web Server (**MUST**)](https://twitter.com/ThePracticalDev/status/892022594031017988) -### HTTP Listening +### Structuring + +Nothing stops you from using your favorite folder structure. Iris is a low level web framework, it has got MVC support but it doesn't limit your folder structure, this is your choice. + +Structuring is always depends on your needs. We can't tell you how to design your own application for sure but you're free to take a closer look to the examples below; you may find something useful that you can borrow for your app + +- [Example 1](mvc/login) +- [Example 2](structuring/mvc) + +### HTTP Listening - [Common, with address](http-listening/listen-addr/main.go) * [omit server errors](http-listening/listen-addr/omit-server-errors/main.go) diff --git a/_examples/file-server/basic/assets/favicon.ico b/_examples/file-server/basic/assets/favicon.ico index 961ef6da..c370da51 100644 Binary files a/_examples/file-server/basic/assets/favicon.ico and b/_examples/file-server/basic/assets/favicon.ico differ diff --git a/_examples/file-server/embedding-files-into-app/assets/favicon.ico b/_examples/file-server/embedding-files-into-app/assets/favicon.ico index 961ef6da..c370da51 100644 Binary files a/_examples/file-server/embedding-files-into-app/assets/favicon.ico and b/_examples/file-server/embedding-files-into-app/assets/favicon.ico differ diff --git a/_examples/file-server/favicon/static/favicons/favicon.ico b/_examples/file-server/favicon/static/favicons/favicon.ico index 961ef6da..c370da51 100644 Binary files a/_examples/file-server/favicon/static/favicons/favicon.ico and b/_examples/file-server/favicon/static/favicons/favicon.ico differ diff --git a/_examples/routing/overview/public/images/favicon.ico b/_examples/routing/overview/public/images/favicon.ico index 961ef6da..c370da51 100644 Binary files a/_examples/routing/overview/public/images/favicon.ico and b/_examples/routing/overview/public/images/favicon.ico differ diff --git a/_examples/structuring/mvc/app/app.go b/_examples/structuring/mvc/app/app.go new file mode 100644 index 00000000..cc778676 --- /dev/null +++ b/_examples/structuring/mvc/app/app.go @@ -0,0 +1,144 @@ +package app + +import ( + "fmt" + "time" + + "github.com/gorilla/securecookie" + + "github.com/kataras/iris" + "github.com/kataras/iris/middleware/logger" + "github.com/kataras/iris/middleware/recover" + "github.com/kataras/iris/sessions" + + "github.com/kataras/iris/_examples/structuring/mvc/app/controllers/follower" + "github.com/kataras/iris/_examples/structuring/mvc/app/controllers/following" + "github.com/kataras/iris/_examples/structuring/mvc/app/controllers/index" + "github.com/kataras/iris/_examples/structuring/mvc/app/controllers/like" +) + +// Application is our application wrapper and bootstrapper, keeps our settings. +type Application struct { + *iris.Application + + Name string + Owner string + SpawnDate time.Time + + Sessions *sessions.Sessions +} + +// NewApplication returns a new named Application. +func NewApplication(name, owner string) *Application { + return &Application{ + Name: name, + Owner: owner, + Application: iris.New(), + SpawnDate: time.Now(), + } +} + +// begin sends the app's identification info. +func (app *Application) begin(ctx iris.Context) { + // response headers + ctx.Header("App-Name", app.Name) + ctx.Header("App-Owner", app.Owner) + ctx.Header("App-Since", time.Since(app.SpawnDate).String()) + + ctx.Header("Server", "Iris: https://iris-go.com") + + // view data if ctx.View or c.Tmpl = "$page.html" will be called next. + ctx.ViewData("AppName", app.Name) + ctx.ViewData("AppOwner", app.Owner) + ctx.Next() +} + +// SetupViews loads the templates. +func (app *Application) SetupViews(viewsDir string) { + app.RegisterView(iris.HTML(viewsDir, ".html").Layout("shared/layout.html")) +} + +// SetupSessions initializes the sessions, optionally. +func (app *Application) SetupSessions(expires time.Duration, cookieHashKey, cookieBlockKey []byte) { + app.Sessions = sessions.New(sessions.Config{ + Cookie: "SECRET_SESS_COOKIE_" + app.Name, + Expires: expires, + Encoding: securecookie.New(cookieHashKey, cookieBlockKey), + }) +} + +// SetupErrorHandlers prepares the http error handlers (>=400). +// Remember that error handlers in Iris have their own middleware ecosystem +// so the route's middlewares are not running when an http error happened. +// So if we want a logger we have to re-create one, here we will customize that logger as well. +func (app *Application) SetupErrorHandlers() { + httpErrStatusLogger := logger.New(logger.Config{ + Status: true, + IP: true, + Method: true, + Path: true, + MessageContextKey: "message", + LogFunc: func(now time.Time, latency time.Duration, + status, ip, method, path string, + message interface{}) { + + line := fmt.Sprintf("%v %4v %s %s %s", status, latency, ip, method, path) + + if message != nil { + line += fmt.Sprintf(" %v", message) + } + app.Logger().Warn(line) + }, + }) + + app.OnAnyErrorCode(app.begin, httpErrStatusLogger, func(ctx iris.Context) { + err := iris.Map{ + "app": app.Name, + "status": ctx.GetStatusCode(), + "message": ctx.Values().GetString("message"), + } + + if jsonOutput, _ := ctx.URLParamBool("json"); jsonOutput { + ctx.JSON(err) + return + } + + ctx.ViewData("Err", err) + ctx.ViewData("Title", "Error") + ctx.View("shared/error.html") + }) +} + +// SetupRouter registers the available routes from the "controllers" package. +func (app *Application) SetupRouter() { + app.Use(recover.New()) + app.Use(app.begin) + app.Use(iris.Gzip) + + app.Favicon("./public/favicon.ico") + app.StaticWeb("/public", "./public") + + app.Use(logger.New()) + + app.Controller("/", new(index.Controller)) + app.Controller("/follower", new(follower.Controller)) + app.Controller("/following", new(following.Controller)) + app.Controller("/like", new(like.Controller)) +} + +// Instance is our global application bootstrap instance. +var Instance = NewApplication("My Awesome App", "kataras2006@hotmail.com") + +// Boot starts our default instance appolication. +func Boot(runner iris.Runner, configurators ...iris.Configurator) { + Instance.SetupViews("./app/views") + Instance.SetupSessions(24*time.Hour, + []byte("the-big-and-secret-fash-key-here"), + []byte("lot-secret-of-characters-big-too"), + ) + + Instance.SetupErrorHandlers() + Instance.SetupRouter() + + Instance.Run(runner, configurators...) +} diff --git a/_examples/structuring/mvc/app/controllers/follower/controller.go b/_examples/structuring/mvc/app/controllers/follower/controller.go new file mode 100644 index 00000000..dd06ad13 --- /dev/null +++ b/_examples/structuring/mvc/app/controllers/follower/controller.go @@ -0,0 +1,13 @@ +package follower + +import ( + "github.com/kataras/iris" +) + +type Controller struct { + iris.Controller +} + +func (c *Controller) GetBy(id int64) { + c.Ctx.Writef("from "+c.Route().Path()+" with ID: %d", id) +} diff --git a/_examples/structuring/mvc/app/controllers/following/controller.go b/_examples/structuring/mvc/app/controllers/following/controller.go new file mode 100644 index 00000000..9de54d05 --- /dev/null +++ b/_examples/structuring/mvc/app/controllers/following/controller.go @@ -0,0 +1,13 @@ +package following + +import ( + "github.com/kataras/iris" +) + +type Controller struct { + iris.Controller +} + +func (c *Controller) GetBy(id int64) { + c.Ctx.Writef("from "+c.Route().Path()+" with ID: %d", id) +} diff --git a/_examples/structuring/mvc/app/controllers/index/controller.go b/_examples/structuring/mvc/app/controllers/index/controller.go new file mode 100644 index 00000000..40101fbb --- /dev/null +++ b/_examples/structuring/mvc/app/controllers/index/controller.go @@ -0,0 +1,14 @@ +package index + +import ( + "github.com/kataras/iris" +) + +type Controller struct { + iris.Controller +} + +func (c *Controller) Get() { + c.Data["Title"] = "Index" + c.Tmpl = "index.html" +} diff --git a/_examples/structuring/mvc/app/controllers/like/controller.go b/_examples/structuring/mvc/app/controllers/like/controller.go new file mode 100644 index 00000000..851c3267 --- /dev/null +++ b/_examples/structuring/mvc/app/controllers/like/controller.go @@ -0,0 +1,13 @@ +package like + +import ( + "github.com/kataras/iris" +) + +type Controller struct { + iris.Controller +} + +func (c *Controller) GetBy(id int64) { + c.Ctx.Writef("from "+c.Route().Path()+" with ID: %d", id) +} diff --git a/_examples/structuring/mvc/app/views/index.html b/_examples/structuring/mvc/app/views/index.html new file mode 100644 index 00000000..4a813af6 --- /dev/null +++ b/_examples/structuring/mvc/app/views/index.html @@ -0,0 +1 @@ +