# Handle Errors

The MVC Application or a Controller's error handling varies based on the type of error and its source. In this section you learn how to handle each error depending of its type (e.g. http error like 404, response error from a method or a failure while a method trying to render a response). A Controller can use all the methods at once when it's necessary.

## HTTP Errors

Let's start by the most critual one, handle HTTP errors per Controller.

To register an HTTP error handler the Controller (or one of its embedded fields) MUST contain a method named `HandleHTTPError`. That method can accept and output any type of arguments to render a response, like the rest of the Controller's method. The `HandleHTTPError` is automatically called by the Framework on HTTP Errors (client 4xx or server 5xx).

*Example Code:*

The following code snippet will render "errors/404.html" on 404 Not Found, "errors/500.html" on 500 Internal Server Error and e.t.c.

```go
func (c *Base) HandleHTTPError(err mvc.Err, statusCode mvc.Code) mvc.View {
    if err != nil {
        // Do something with that error,
        // e.g. view.Data = MyPageData{Message: err.Error()}
    }

	code := int(statusCode) // cast it to int.

	return mvc.View{
		Code: code,
		Name: fmt.Sprintf("errors/%d.html", code),
	}
}
```

The input parameter of `mvc.Code` is optional but a good practise to follow. You could register a Context and get its error code through `ctx.GetStatusCode()`.

This can accept dependencies and output values like any other Controller Method, however be careful if your registered dependencies depend only on successful(200...) requests.

Let's write a method which can fire `HandleHTTPError`. This is totally optional as `HandleHTTPError` will be called automatically on HTTP errors (e.g. client 404).

```go
func (c *UserController) GetError() mvc.Result {
	return mvc.View{
		// Map to mvc.Code and mvc.Err respectfully on HandleHTTPError method.
		Code: iris.StatusBadRequest,
		Err:  fmt.Errorf("custom error"),
    }

    // OR mvc.Response{Code: ... Err: ...}
    // OR ctx.StatusCode(...) and ctx.SetErr(...)
    // OR return an (int, error) instead.
}
```

Also note that, if you register more than one `HandleHTTPError` in the same `Party`, you need to use the `RouteOverlap` feature as shown in the [authenticated-controller](https://github.com/kataras/iris/blob/00684f9d2e8e5d6af952405f07f11093e7be29bd/_examples/mvc/authenticated-controller/main.go#L43) example.

## Custom Errors

A Controller's method can return a custom structure which is responsible to render a response based on given data. This error can be an HTTP Error or a view with 2xx Status OK or a redirect response with 3xx status code.

This can be achieved through a custom `mvc.Result` or `mvc.Preflight` (as we've shown at the previous sections).

### Using a `mvc.Result`

Good method to use when `mvc.Result` is returned from the Controller's method.

Let's create a custom Go structure with some data used to render the response.

```go
type errorResponse struct {
	Code    int
	Message string
}
```

Implement the `mvc.Result` through the `Dispatch(iris.Context)` method.

```go
func (e errorResponse) Dispatch(ctx iris.Context) {
	view := mvc.View{
        Code: e.Code,
        Data: e,
        Name: fmt.Sprintf("errors/%d.html", e.Code),
    }

	view.Dispatch(ctx)
}
```

> Remember: mvc.View, Response and e.t.c are all mvc.Result at the end, so you can call their Dispatch method to render even if a specific method cannot output values (like this `Dispatch` one).

Alternatively, using just the Context's methods:

```go
func (e errorResponse) Dispatch(ctx iris.Context) {
    viewName := fmt.Sprintf("errors/%d.html", e.Code)

    ctx.StatusCode(e.Code)
    ctx.View(viewName, e)
}
```

**Usage**

It's time to use our `errorResponse`. Let's design a `GetBy` method which returns `mvc.Result`, it returns an `errorResponse` when "user" was not found in our "database".

```go
func (c *UserController) GetBy(id uint64) mvc.Result {
	user, found, err := c.DB.Single(
        "SELECT * FROM users WHERE user_id=? LIMIT 1",
	    id)
	if !found {
		return errorResponse{
			Code:    iris.StatusNotFound,
			Message: "User Not Found",
		}
	}

	// [...]
}
```

### Using a `mvc.Preflight`

Good method to use when a return value type might be or might not complete `mvc.Result` or `mvc.Preflight` interfaces. E.g. a single `response` which can output data or error. Or even return different types at all, e.g. return a `user struct` (JSON by default) on valid requests and `userError mvc.Preflight` on failures. Read more about output values in the dependency injection section.

```go
// Generic response type for JSON results.
type response struct {
	ID        uint64      `json:"id,omitempty"`
	Data      interface{} `json:"data,omitempty"`
	Code      int         `json:"code,omitempty"`
	Message   string      `json:"message,omitempty"`
	Timestamp int64       `json:"timestamp,omitempty"`
}
```

Complete the `mvc.Preflight` interface which will run right before the render of `response`, it can manipulate an object right before it is rendered or handle rendering all by it self by returning the `iris.ErrStopExecution` error.

```go
func (r response) Preflight(ctx iris.Context) error {
	r.Timestamp = time.Now().Unix()

	if r.Code > 0 {
		// You can call ctx.View or mvc.Vew{...}.Dispatch
		// to render HTML on Code >= 400
		// but in order to not proceed with the response resulting
		// as JSON you MUST return the iris.ErrStopExecution error.
		// Example:
		if r.Code >= 400 && ctx.GetContentTypeRequested() == "text/html" {
			// If code is a client or server error,
			// render a template using mvc.View (you can use ctx.View too).
			mvc.View{
				/* calls the ctx.StatusCode */
				Code: r.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("errors/%d.html", r.Code),
			}.Dispatch(ctx)

			return iris.ErrStopExecution
		}

		// Else just write the status code based on the given struct's value,
		// see Controller method below.
		ctx.StatusCode(r.Code)
	}

	return nil
}
```

**Usage**

Let's use our `response` type to a Controller's method. The `User` structure will be embedded into our `response.Data` field.

```go
type User struct {
	ID uint64 `json:"id"`
}

func (c *Controller) GetBy(userid uint64) response {
    user, found, err := c.DB.Single(
        "SELECT * FROM users WHERE user_id=? LIMIT 1",
        id)
	if !found {
		return response{
			Code:    iris.StatusNotFound,
			Message: "User Not Found",
		}
	}

	return response{
		ID:   userid,
		Data: User{
			ID: userid,
		},
	}
}
```

> Remember: A structure can complete both mvc.Result and mvc.Preflight interfaces. If Preflight does not return `iris.ErrStopExecution` then it proceeds with the `Dispatch` (mvc.Result) method one. Here is the [underline code](https://github.com/kataras/iris/blob/600eb645dfb7b5cf98d8e1c271e39309e870657f/hero/func_result.go#L16-L51).

The above example will render HTML errors when the client accepts html, otherwise will render both error and result as JSON. This method is the recommended one when designing APIs for 3rd-party programmers.

### Hijack a Controller Method Result

There is one more option for advanced scenarios. Register a custom `ResultHandler` when you want to manipulate or change or log each controllers methods return values per MVC Application or globally.

Example Code:

```go
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}
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://iris-go.gitbook.io/iris/mvc/mvc-error.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
