diff --git a/HISTORY.md b/HISTORY.md
index 27b0b46c..36ee96a5 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -242,7 +242,10 @@ func (r *response) Preflight(ctx iris.Context) error {
r.Timestamp = time.Now().Unix()
}
- ctx.StatusCode(r.Code)
+ if r.Code > 0 {
+ ctx.StatusCode(r.Code)
+ }
+
return nil
}
```
diff --git a/README.md b/README.md
index 5a3a2a09..9b40c6e6 100644
--- a/README.md
+++ b/README.md
@@ -215,7 +215,7 @@ For a more detailed technical documentation you can head over to our [godocs](ht
[](https://twitter.com/intent/follow?screen_name=iris_framework)
-[](https://www.facebook.com/iris.framework)
+[](https://www.facebook.com/iris.framework)
You can [request](https://iris-go.com/#book) a PDF version and online access of the **E-Book** today and be participated in the development of Iris.
diff --git a/_examples/README.md b/_examples/README.md
index 7754fdbf..ffbd3783 100644
--- a/_examples/README.md
+++ b/_examples/README.md
@@ -214,6 +214,10 @@
* [Login (Repository and Service layers)](mvc/login)
* [Login (Single Responsibility)](mvc/login-mvc-single-responsibility)
* [Vue.js Todo App](mvc/vuejs-todo-mvc)
+ * [Error Handler](mvc/error-handler)
+ * [Handle errors using mvc.Result](mvc/error-handler-custom-result)
+ * [Handle errors using PreflightResult](mvc/error-handler-preflight)
+ * [Handle errors by hijacking the result](mvc/error-handler-hijack)
* [Bootstrapper](bootstrapper)
* Desktop Applications
* [The blink package](desktop/blink)
diff --git a/_examples/mvc/error-handler-custom-result/main.go b/_examples/mvc/error-handler-custom-result/main.go
new file mode 100644
index 00000000..c9805c8e
--- /dev/null
+++ b/_examples/mvc/error-handler-custom-result/main.go
@@ -0,0 +1,75 @@
+package main
+
+import (
+ "github.com/kataras/iris/v12"
+ "github.com/kataras/iris/v12/mvc"
+)
+
+func main() {
+ app := iris.New()
+ app.RegisterView(iris.HTML("./views", ".html"))
+
+ m := mvc.New(app)
+ m.Handle(new(controller))
+
+ app.Listen(":8080")
+}
+
+type errorResponse struct {
+ Code int
+ Message string
+}
+
+/*
+// Note: if a struct implements the standard go error, so it's an error
+// and its Error() is not empty, then its text will be rendered instead,
+// override any Dispatch method.
+func (e errorResponse) Error() string {
+ return e.Message
+}
+*/
+
+// implements mvc.Result.
+func (e errorResponse) Dispatch(ctx iris.Context) {
+ // If u want to use mvc.Result on any method without an output return value
+ // go for it:
+ //
+ view := mvc.View{Code: e.Code, Data: e} // use Code and Message as the template data.
+ switch e.Code {
+ case iris.StatusNotFound:
+ view.Name = "404"
+ default:
+ view.Name = "500"
+ }
+ view.Dispatch(ctx)
+
+ // Otherwise use ctx methods:
+ //
+ // ctx.StatusCode(e.Code)
+ // switch e.Code {
+ // case iris.StatusNotFound:
+ // // use Code and Message as the template data.
+ // ctx.View("404.html", e)
+ // default:
+ // ctx.View("500.html", e)
+ // }
+}
+
+type controller struct{}
+
+type user struct {
+ ID uint64 `json:"id"`
+}
+
+func (c *controller) GetBy(userid uint64) mvc.Result {
+ if userid != 1 {
+ return errorResponse{
+ Code: iris.StatusNotFound,
+ Message: "User Not Found",
+ }
+ }
+
+ return mvc.Response{
+ Object: user{ID: userid},
+ }
+}
diff --git a/_examples/mvc/error-handler-custom-result/views/404.html b/_examples/mvc/error-handler-custom-result/views/404.html
new file mode 100644
index 00000000..39b8326d
--- /dev/null
+++ b/_examples/mvc/error-handler-custom-result/views/404.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Client Error Page
+
+
+ {{.Code}}
+ {{.Message}}
+
+
\ No newline at end of file
diff --git a/_examples/mvc/error-handler-custom-result/views/500.html b/_examples/mvc/error-handler-custom-result/views/500.html
new file mode 100644
index 00000000..38b44ab3
--- /dev/null
+++ b/_examples/mvc/error-handler-custom-result/views/500.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Server Error Page
+
+
+ {{.Code}}
+ {{.Message}}
+
+
\ No newline at end of file
diff --git a/_examples/mvc/error-handler-hijack/main.go b/_examples/mvc/error-handler-hijack/main.go
new file mode 100644
index 00000000..f471e371
--- /dev/null
+++ b/_examples/mvc/error-handler-hijack/main.go
@@ -0,0 +1,60 @@
+package main
+
+import (
+ "github.com/kataras/iris/v12"
+ "github.com/kataras/iris/v12/mvc"
+)
+
+func main() {
+ app := iris.New()
+ app.RegisterView(iris.HTML("./views", ".html"))
+
+ // Hijack each output value of a method (can be used per-party too).
+ app.ConfigureContainer().
+ UseResultHandler(func(next iris.ResultHandler) iris.ResultHandler {
+ return func(ctx iris.Context, v interface{}) error {
+ switch val := v.(type) {
+ case errorResponse:
+ return next(ctx, errorView(val))
+ default:
+ return next(ctx, v)
+ }
+ }
+ })
+
+ m := mvc.New(app)
+ m.Handle(new(controller))
+
+ app.Listen(":8080")
+}
+
+func errorView(e errorResponse) mvc.Result {
+ switch e.Code {
+ case iris.StatusNotFound:
+ return mvc.View{Code: e.Code, Name: "404.html", Data: e}
+ default:
+ return mvc.View{Code: e.Code, Name: "500.html", Data: e}
+ }
+}
+
+type errorResponse struct {
+ Code int
+ Message string
+}
+
+type controller struct{}
+
+type user struct {
+ ID uint64 `json:"id"`
+}
+
+func (c *controller) GetBy(userid uint64) interface{} {
+ if userid != 1 {
+ return errorResponse{
+ Code: iris.StatusNotFound,
+ Message: "User Not Found",
+ }
+ }
+
+ return user{ID: userid}
+}
diff --git a/_examples/mvc/error-handler-hijack/views/404.html b/_examples/mvc/error-handler-hijack/views/404.html
new file mode 100644
index 00000000..39b8326d
--- /dev/null
+++ b/_examples/mvc/error-handler-hijack/views/404.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Client Error Page
+
+
+ {{.Code}}
+ {{.Message}}
+
+
\ No newline at end of file
diff --git a/_examples/mvc/error-handler-hijack/views/500.html b/_examples/mvc/error-handler-hijack/views/500.html
new file mode 100644
index 00000000..38b44ab3
--- /dev/null
+++ b/_examples/mvc/error-handler-hijack/views/500.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Server Error Page
+
+
+ {{.Code}}
+ {{.Message}}
+
+
\ No newline at end of file
diff --git a/_examples/mvc/error-handler-preflight/main.go b/_examples/mvc/error-handler-preflight/main.go
new file mode 100644
index 00000000..34289a95
--- /dev/null
+++ b/_examples/mvc/error-handler-preflight/main.go
@@ -0,0 +1,101 @@
+package main
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/kataras/iris/v12"
+ "github.com/kataras/iris/v12/mvc"
+)
+
+func main() {
+ app := iris.New()
+ app.RegisterView(iris.HTML("./views", ".html"))
+
+ m := mvc.New(app)
+ m.Handle(new(controller))
+
+ app.Listen(":8080")
+}
+
+type controller struct{}
+
+// Generic response type for JSON results.
+type response struct {
+ ID uint64 `json:"id,omitempty"`
+ Data interface{} `json:"data,omitempty"` // {data: result } on fetch actions.
+ Code int `json:"code,omitempty"`
+ Message string `json:"message,omitempty"`
+ Timestamp int64 `json:"timestamp,omitempty"`
+}
+
+func (r response) Preflight(ctx iris.Context) error {
+ if r.ID > 0 {
+ r.Timestamp = time.Now().Unix()
+ }
+
+ if code := r.Code; code > 0 {
+ // You can call ctx.View or mvc.Vew{...}.Dispatch
+ // to render HTML on Code != 200
+ // but in order to not proceed with the response resulting
+ // as JSON you MUST return the iris.ErrStopExecution error.
+ // Example:
+ if code != 200 {
+ mvc.View{
+ /* calls the ctx.StatusCode */
+ Code: code,
+ /* use any r.Data as the template data
+ OR the whole "response" as its data. */
+ Data: r,
+ /* automatically pick the template per error (just for the sake of the example) */
+ Name: fmt.Sprintf("%d", code),
+ }.Dispatch(ctx)
+
+ return iris.ErrStopExecution
+ }
+
+ ctx.StatusCode(r.Code)
+ }
+
+ return nil
+}
+
+type user struct {
+ ID uint64 `json:"id"`
+}
+
+func (c *controller) GetBy(userid uint64) response {
+ if userid != 1 {
+ return response{
+ Code: iris.StatusNotFound,
+ Message: "User Not Found",
+ }
+ }
+
+ return response{
+ ID: userid,
+ Data: user{ID: userid},
+ }
+}
+
+/*
+
+You can use that `response` structure on non-mvc applications too, using handlers:
+
+c := app.ConfigureContainer()
+c.Get("/{id:uint64}", getUserByID)
+func getUserByID(id uint64) response {
+ if userid != 1 {
+ return response{
+ Code: iris.StatusNotFound,
+ Message: "User Not Found",
+ }
+ }
+
+ return response{
+ ID: userid,
+ Data: user{ID: userid},
+ }
+}
+
+*/
diff --git a/_examples/mvc/error-handler-preflight/views/404.html b/_examples/mvc/error-handler-preflight/views/404.html
new file mode 100644
index 00000000..39b8326d
--- /dev/null
+++ b/_examples/mvc/error-handler-preflight/views/404.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Client Error Page
+
+
+ {{.Code}}
+ {{.Message}}
+
+
\ No newline at end of file
diff --git a/_examples/mvc/error-handler-preflight/views/500.html b/_examples/mvc/error-handler-preflight/views/500.html
new file mode 100644
index 00000000..38b44ab3
--- /dev/null
+++ b/_examples/mvc/error-handler-preflight/views/500.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Server Error Page
+
+
+ {{.Code}}
+ {{.Message}}
+
+
\ No newline at end of file
diff --git a/hero/func_result.go b/hero/func_result.go
index 74bd56a3..964cb6fe 100644
--- a/hero/func_result.go
+++ b/hero/func_result.go
@@ -72,6 +72,9 @@ type Result interface {
//
// The caller can manage it at the handler itself. However,
// to reduce thoese type of duplications it's preferable to use such a standard interface instead.
+//
+// The Preflight method can return `iris.ErrStopExecution` to render
+// and override any interface that the structure value may implement, e.g. mvc.Result.
type PreflightResult interface {
Preflight(*context.Context) error
}
diff --git a/hero/func_result_test.go b/hero/func_result_test.go
index e89b80d8..dcb76dc9 100644
--- a/hero/func_result_test.go
+++ b/hero/func_result_test.go
@@ -223,7 +223,10 @@ func (r testPreflightResponse) Preflight(ctx iris.Context) error {
return fmt.Errorf("custom error")
}
- ctx.StatusCode(r.Code)
+ if r.Code > 0 {
+ ctx.StatusCode(r.Code)
+ }
+
return nil
}