add a new 'overview' MVC example

Former-commit-id: f73cbf6010595c639f6c5b5119e2ec41bc9802a5
This commit is contained in:
Gerasimos (Makis) Maropoulos 2020-06-21 00:12:07 +03:00
parent 45c6bce15f
commit d55bb34766
29 changed files with 361 additions and 148 deletions

View File

@ -2,7 +2,7 @@
> This is the under-development branch. Stay tuned for the upcoming release [v12.2.0](HISTORY.md#Next).
![](https://iris-go.com/images/release.png) Iris version **12.1.8** has been [released](HISTORY.md#su-16-february-2020--v1218)!
<!-- ![](https://iris-go.com/images/release.png) Iris version **12.1.8** has been [released](HISTORY.md#su-16-february-2020--v1218)! -->
![](https://iris-go.com/images/cli.png) The official [Iris Command Line Interface](https://github.com/kataras/iris-cli) will soon be near you in 2020!
@ -31,7 +31,7 @@ Learn what [others saying about Iris](https://iris-go.com/testimonials/) and **[
```sh
# https://github.com/kataras/iris/wiki/Installation
$ go get github.com/kataras/iris/v12@latest
$ go get github.com/kataras/iris/v12@master
# assume the following code in example.go file
$ cat example.go
```
@ -67,7 +67,7 @@ Iris contains extensive and thorough **[wiki](https://github.com/kataras/iris/wi
<!-- ![](https://media.giphy.com/media/Ur8iqy9FQfmPuyQpgy/giphy.gif) -->
For a more detailed technical documentation you can head over to our [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.0). And for executable code you can always visit the [\_examples](_examples/) repository's subdirectory.
For a more detailed technical documentation you can head over to our [godocs](https://godoc.org/github.com/kataras/iris). And for executable code you can always visit the [./_examples](_examples) repository's subdirectory.
### Do you like to read while traveling?

View File

@ -182,7 +182,8 @@
* [JWT](dependency-injection/jwt/main.go)
* [JWT (iris-contrib)](dependency-injection/jwt/contrib/main.go)
* MVC
* [Overview - Repository and Service layers](mvc/overview)
* [Overview](mvc/overview)
* [Repository and Service layers](mvc/repository)
* [Hello world](mvc/hello-world/main.go)
* [Basic](mvc/basic/main.go)
* [Wildcard](mvc/basic/wildcard/main.go)

View File

@ -0,0 +1,23 @@
package controller
import (
"app/model"
"app/service"
)
// GreetController handles the index.
type GreetController struct {
Service service.GreetService
// Ctx iris.Context
}
// Get serves [GET] /.
// Query: name
func (c *GreetController) Get(req model.Request) (model.Response, error) {
message, err := c.Service.Say(req.Name)
if err != nil {
return model.Response{}, err
}
return model.Response{Message: message}, nil
}

View File

@ -0,0 +1,22 @@
package database
import (
"app/environment"
)
// DB example database interface.
type DB interface {
Exec(q string) error
}
// NewDB returns a database based on "env".
func NewDB(env environment.Env) DB {
switch env {
case environment.PROD:
return &mysql{}
case environment.DEV:
return &sqlite{}
default:
panic("unknown environment")
}
}

View File

@ -0,0 +1,10 @@
package database
import "fmt"
type mysql struct{}
func (db *mysql) Exec(q string) error {
// simulate an error response.
return fmt.Errorf("mysql: not implemented <%s>", q)
}

View File

@ -0,0 +1,5 @@
package database
type sqlite struct{}
func (db *sqlite) Exec(q string) error { return nil }

View File

@ -0,0 +1,10 @@
package environment
// Env is the environment type.
type Env string
// Available environments example.
const (
PROD Env = "production"
DEV Env = "development"
)

View File

@ -0,0 +1,3 @@
module app
go 1.14

View File

@ -1,13 +1,10 @@
// file: main.go
package main
import (
"github.com/kataras/iris/v12/_examples/mvc/overview/datasource"
"github.com/kataras/iris/v12/_examples/mvc/overview/repositories"
"github.com/kataras/iris/v12/_examples/mvc/overview/services"
"github.com/kataras/iris/v12/_examples/mvc/overview/web/controllers"
"github.com/kataras/iris/v12/_examples/mvc/overview/web/middleware"
"app/controller"
"app/database"
"app/environment"
"app/service"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/mvc"
@ -15,39 +12,66 @@ import (
func main() {
app := iris.New()
app.Logger().SetLevel("debug")
mvc.Configure(app.Party("/greet"), setup)
// Load the template files.
app.RegisterView(iris.HTML("./web/views", ".html"))
// Serve our controllers.
mvc.New(app.Party("/hello")).Handle(new(controllers.HelloController))
// You can also split the code you write to configure an mvc.Application
// using the `mvc.Configure` method, as shown below.
mvc.Configure(app.Party("/movies"), movies)
// http://localhost:8080/hello
// http://localhost:8080/hello/iris
// http://localhost:8080/movies
// http://localhost:8080/movies/1
app.Listen(":8080", iris.WithOptimizations)
// http://localhost:8080/greet?name=kataras
app.Listen(":8080", iris.WithLogLevel("debug"))
}
// note the mvc.Application, it's not iris.Application.
func movies(app *mvc.Application) {
// Add the basic authentication(admin:password) middleware
// for the /movies based requests.
app.Router.Use(middleware.BasicAuth)
/*
+-------------------+
| Env (DEV, PROD) |
+---------+---------+
| | |
| | |
| | |
DEV | | | PROD
-------------------+---------------------+ | +----------------------+-------------------
| | |
| | |
+---+-----+ +----------------v------------------+ +----+----+
| sqlite | | NewDB(Env) DB | | mysql |
+---+-----+ +----------------+---+--------------+ +----+----+
| | | |
| | | |
| | | |
+------------+-----+ +-------------------v---v-----------------+ +----+------+
| greeterWithLog | | NewGreetService(Env, DB) GreetService | | greeter |
-------------+-----+ +---------------------------+-------------+ +----+------+
| | |
| | |
| +-----------------------------------------+ |
| | GreetController | | |
| | | | |
| | - Service GreetService <-- | |
| | | |
| +-------------------+---------------------+ |
| | |
| | |
| | |
| +-----------+-----------+ |
| | HTTP Request | |
| +-----------------------+ |
| | /greet?name=kataras | |
| +-----------+-----------+ |
| | |
+------------------+--------+ +------------+------------+ +-------+------------------+
| model.Response (JSON) | | Response (JSON, error) | | Bad Request |
+---------------------------+ +-------------------------+ +--------------------------+
| { | | mysql: not implemented |
| "msg": "Hello kataras" | +--------------------------+
| } |
+---------------------------+
*/
func setup(app *mvc.Application) {
// Register Dependencies.
// Tip: A dependency can depend on other dependencies too.
app.Register(
environment.DEV, // DEV, PROD
database.NewDB, // sqlite, mysql
service.NewGreetService, // greeterWithLogging, greeter
)
// Create our movie repository with some (memory) data from the datasource.
repo := repositories.NewMovieRepository(datasource.Movies)
// Create our movie service, we will bind it to the movie app's dependencies.
movieService := services.NewMovieService(repo)
app.Register(movieService)
// serve our movies controller.
// Note that you can serve more than one controller
// you can also create child mvc apps using the `movies.Party(relativePath)` or `movies.Clone(app.Party(...))`
// if you want.
app.Handle(new(controllers.MovieController))
// Register Controllers.
app.Handle(new(controller.GreetController))
}

View File

@ -0,0 +1,6 @@
package model
// Request example incoming request.
type Request struct {
Name string `json:"name" url:"name"`
}

View File

@ -0,0 +1,6 @@
package model
// Response example server's response.
type Response struct {
Message string `json:"msg"`
}

View File

@ -0,0 +1,50 @@
package service
import (
"app/database"
"app/environment"
"fmt"
)
// GreetService example service.
type GreetService interface {
Say(input string) (string, error)
}
// NewGreetService returns a service backed with a "db" based on "env".
func NewGreetService(env environment.Env, db database.DB) GreetService {
service := &greeter{db: db, prefix: "Hello"}
switch env {
case environment.PROD:
return service
case environment.DEV:
return &greeterWithLogging{service}
default:
panic("unknown environment")
}
}
type greeter struct {
prefix string
db database.DB
}
func (s *greeter) Say(input string) (string, error) {
if err := s.db.Exec("simulate a query..."); err != nil {
return "", err
}
result := s.prefix + " " + input
return result, nil
}
type greeterWithLogging struct {
*greeter
}
func (s *greeterWithLogging) Say(input string) (string, error) {
result, err := s.greeter.Say(input)
fmt.Printf("result: %s\nerror: %v\n", result, err)
return result, err
}

View File

@ -2,7 +2,7 @@
package datasource
import "github.com/kataras/iris/v12/_examples/mvc/overview/datamodels"
import "github.com/kataras/iris/v12/_examples/mvc/repository/datamodels"
// Movies is our imaginary data source.
var Movies = map[int64]datamodels.Movie{

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -0,0 +1,53 @@
// file: main.go
package main
import (
"github.com/kataras/iris/v12/_examples/mvc/repository/datasource"
"github.com/kataras/iris/v12/_examples/mvc/repository/repositories"
"github.com/kataras/iris/v12/_examples/mvc/repository/services"
"github.com/kataras/iris/v12/_examples/mvc/repository/web/controllers"
"github.com/kataras/iris/v12/_examples/mvc/repository/web/middleware"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/mvc"
)
func main() {
app := iris.New()
app.Logger().SetLevel("debug")
// Load the template files.
app.RegisterView(iris.HTML("./web/views", ".html"))
// Serve our controllers.
mvc.New(app.Party("/hello")).Handle(new(controllers.HelloController))
// You can also split the code you write to configure an mvc.Application
// using the `mvc.Configure` method, as shown below.
mvc.Configure(app.Party("/movies"), movies)
// http://localhost:8080/hello
// http://localhost:8080/hello/iris
// http://localhost:8080/movies
// http://localhost:8080/movies/1
app.Listen(":8080", iris.WithOptimizations)
}
// note the mvc.Application, it's not iris.Application.
func movies(app *mvc.Application) {
// Add the basic authentication(admin:password) middleware
// for the /movies based requests.
app.Router.Use(middleware.BasicAuth)
// Create our movie repository with some (memory) data from the datasource.
repo := repositories.NewMovieRepository(datasource.Movies)
// Create our movie service, we will bind it to the movie app's dependencies.
movieService := services.NewMovieService(repo)
app.Register(movieService)
// serve our movies controller.
// Note that you can serve more than one controller
// you can also create child mvc apps using the `movies.Party(relativePath)` or `movies.Clone(app.Party(...))`
// if you want.
app.Handle(new(controllers.MovieController))
}

View File

@ -5,7 +5,7 @@ There should be the domain/business-level models.
Example:
```go
import "github.com/kataras/iris/v12/_examples/mvc/overview/datamodels"
import "github.com/kataras/iris/v12/_examples/mvc/repository/datamodels"
type Movie struct {
datamodels.Movie

View File

@ -6,7 +6,7 @@ import (
"errors"
"sync"
"github.com/kataras/iris/v12/_examples/mvc/overview/datamodels"
"github.com/kataras/iris/v12/_examples/mvc/repository/datamodels"
)
// Query represents the visitor and action queries.

View File

@ -3,8 +3,8 @@
package services
import (
"github.com/kataras/iris/v12/_examples/mvc/overview/datamodels"
"github.com/kataras/iris/v12/_examples/mvc/overview/repositories"
"github.com/kataras/iris/v12/_examples/mvc/repository/datamodels"
"github.com/kataras/iris/v12/_examples/mvc/repository/repositories"
)
// MovieService handles some of the CRUID operations of the movie datamodel.

View File

@ -5,8 +5,8 @@ package controllers
import (
"errors"
"github.com/kataras/iris/v12/_examples/mvc/overview/datamodels"
"github.com/kataras/iris/v12/_examples/mvc/overview/services"
"github.com/kataras/iris/v12/_examples/mvc/repository/datamodels"
"github.com/kataras/iris/v12/_examples/mvc/repository/services"
"github.com/kataras/iris/v12"
)

View File

@ -6,7 +6,7 @@ Example:
```go
import (
"github.com/kataras/iris/v12/_examples/mvc/overview/datamodels"
"github.com/kataras/iris/v12/_examples/mvc/repository/datamodels"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/context"