# Middleware

Middleware in Iris is a way of running code before or after the main handler of an HTTP request. For example, a middleware called "logger" could write the request details to a file or the console, before passing the control to the main handler. Middleware is very flexible and reusable within and across your applications!

A middleware is simply an [iris.Handler](https://pkg.go.dev/github.com/kataras/iris/v12/context#Handler) that has the signature `func(ctx iris.Context)`. Each middleware is executed when the previous one calls the `ctx.Next()` method, which can be used for authentication, i.e., if the request is not authorized, we could send an error response instead of calling this method.

**Iris offers 7 (+1) different ways to register middleware, depending on your application's needs.** [Party.UseError](https://pkg.go.dev/github.com/kataras/iris/v12/core/router#APIBuilder.UseError), [Party.Use](https://pkg.go.dev/github.com/kataras/iris/v12/core/router#APIBuilder.Use), [Party.UseOnce](https://pkg.go.dev/github.com/kataras/iris/v12/core/router#APIBuilder.UseOnce), [Application.UseGlobal](https://pkg.go.dev/github.com/kataras/iris/v12/core/router#APIBuilder.UseGlobal), [Party.Done](https://pkg.go.dev/github.com/kataras/iris/v12/core/router#APIBuilder.Done), [Application.DoneGlobal](https://pkg.go.dev/github.com/kataras/iris/v12/core/router#APIBuilder.DoneGlobal), [Party.UseRouter](https://pkg.go.dev/github.com/kataras/iris/v12/core/router#APIBuilder.UseRouter) and [Application.WrapRouter](https://pkg.go.dev/github.com/kataras/iris/v12/core/router#Router.WrapRouter). **Iris gives you the tools to have full control over the request flow.**

## Register A Middleware

Let's see how each one of these methods works in practice by registering middlewares in an Iris Application and Party (group of routes). Below you will see a simple example that shows the order of execution of each registered handler to the client.

```go
package main

import (
    "net/http"
    
    "github.com/kataras/iris/v12"
)

func main() {
    app := iris.New()
    
    app.WrapRouter(routerWrapper)
    app.UseRouter(routerMiddleware)
    app.UseGlobal(globalMiddleware)
    app.Use(useMiddleware)
    app.UseError(errorMiddleware)
    // app.Done(done)
    // app.DoneGlobal(doneGlobal)
    
    // Adding a OnErrorCode(iris.StatusNotFound) causes `.UseGlobal`
    // to be fired on 404 pages without this,
    // only `UseError` will be called, and thus should
    // be used for error pages.
    app.OnErrorCode(iris.StatusNotFound, notFoundHandler)
    
    app.Get("/", mainHandler)

    app.Listen(":8080")
}

func mainHandler(ctx iris.Context) {
    ctx.WriteString("Main Handler")
}

func notFoundHandler(ctx iris.Context) {
    ctx.WriteString("404 Error Handler")
}
```

### The `Application.WrapRouter` Method

A [WrapperFunc](https://pkg.go.dev/github.com/kataras/iris/v12/core/router#WrapperFunc) registered in this way runs for the whole Application, **before anything else**. It is executed **last registered first**, unlike other middleware methods. A `WrapperFunc` is **not** an `iris.Handler`, instead its signature is: `func(http.ResponseWriter, *http.Request, router http.HandlerFunc)`. It's the lowest-level functionality used to intercept requests and optionally change the behaviour of the router (e.g. navigate to another route than the requested path one, perform security checks before even the router is executed and more). A good example of use-case is a CORS implementation.

### The `Party.UseRouter` Method

A middleware registered in this way will run under a specific Party's path prefix on all routes (whether they are matched or not, including routes that would result in an error.) All child Parties inherit them unless `Party.ResetRouteFilters()` or `Party.Reset()` is called. They are executed in the order they are registered, and they run before `UseGlobal` and `Use` on matched routes or `UseError` on errors.

### The `Application.UseGlobal` Method

A middleware registered in this way will run on all previous and future routes, and registered error handlers (pages matched with `OnErrorCode`), in the whole Application (all Parties and Subdomains included.) They are also executed in the order they are registered, and they run before `Use` or `UseError`.

### The `Party.Use` Method

A middleware registered in this way will run after `UseGlobal` under a particular Party and its children. They are also executed in the order they are registered, and they run **right before the Handle itself** (such as `Get`, `Post`, `Patch`, ...) **It is not executed on errors.**

### The `Party.UseError` Method

A middleware registered in this way will run only when an HTTP error is encountered (such as the case with an unavailable `404` or protected `401` resources), unlike `Use`. They fire for all children Parties and will be called in the order they were registered.

### The `Party.Done` Method

Register handler to run **after routes middleware and handlers under a specific Party and its children**. Requires a `ctx.Next` call on the last route's handler, unless [Execution Rules](#execution-rules) are modified.

### The `Application.DoneGlobal` Method

Same as `UseGlobal` but for the `Done` handlers. Runs on the Application instance level, **after everything else**.

The middlewares used for this example are included below:

```go
func routerWrapper(w http.ResponseWriter, r *http.Request,
    router http.HandlerFunc) {

    if r.URL.Path == "/" {
        w.Write([]byte("#1 .WrapRouter\n"))
        /* Note for new Gophers:
            If we Write anything here on an error resource in the raw
            `net/http` wrapper like this one, then the response writer will
            automatically send a `200` OK status code (when we first write).
            Any error handler executed after this will not fire as expected.
            Also, when `w.WriteHeader` is called you can NOT change the
            status code later on.

            In Iris Handlers, if you write before the status code has been
            set, then it will also automatically send the 200 OK status
            code which then cannot be changed later. However, if we call
            `ctx.StatusCode` inside an Iris Handler without writing any
            content, then we can change the status code later on. When you
            need to change that behaviour, you must start the handler with
            a `ctx.Record` call.
        */
    }

    // Continue by executing the Iris Router and let it do its job.
    router(w, r)
}


func routerMiddleware(ctx iris.Context) {
    if ctx.Path() == "/" {
        ctx.WriteString("#2 .UseRouter\n")
	// The same caveat described in routerWrapper applies here as well.
    }

    ctx.Next()
}

func globalMiddleware(ctx iris.Context) {
    ctx.WriteString("#3 .UseGlobal\n")
    ctx.Next()
}

func useMiddleware(ctx iris.Context) {
    ctx.WriteString("#4 .Use\n")
    ctx.Next()
}

func errorMiddleware(ctx iris.Context) {
    ctx.WriteString("#3 .UseError\n")
    ctx.Next()
}
```

**Run** our simple application:

```bash
$ go run main.go
Now listening on: http://localhost:8080
Application started. Press CTRL+C to shut down.
```

Point your browser to `http://localhost:8080`, and the output should look exactly like this:

```
#1 .WrapRouter
#2 .UseRouter
#3 .UseGlobal
#4 .Use
Main Handler
```

And for a page that should give a 404, such as `http://localhost:8080/a_not_found_resource`:

```
#3 .UseGlobal
#3 .UseError
404 Error Handler
```

(Note that `WrapRouter` and `UseRouter` are still fired 1st and 2nd, just not shown in the output. Read the block comment to learn why.)

**However, without an `OnErrorCode`**:

It is important to note that without `OnErrorCode` registered, your `UseGlobal` will not be executed.

```
#3 .UseError
Not Found
```

## Modify A Middleware

You can modify the behavior of any existing middleware by wrapping it.

Let's take, for example, that you want to register a middleware on `UseRouter` to run everywhere except on the `static.example.com` subdomain.

You have two ways to do that. The first one is:

```go
package main

import (
    "github.com/kataras/iris/v12"
    "github.com/kataras/iris/v12/middleware/basicauth"
)

func main() {
    users := map[string]string{"username":"password"}
    auth := basicauth.Default(users)

    app.UseRouter(skipStaticSubdomain(auth)) // <--

    // [...]
    app.Listen(":80")
}

func skipStaticSubdomain(handler iris.Handler) iris.Handler {
    return func(ctx iris.Context) {
        if ctx.Subdomain() == "static." {
            // continue to the next or main handler and exit.
            ctx.Next()
            return
        }

        handler(ctx)   
    }
}
```

And the second way is by using the [iris.NewConditionalHandler](https://github.com/kataras/iris/blob/d44b69faed7538aeb4a05ec72ec664fbee7f5c04/_examples/routing/conditional-chain/main.go#L40):

```go
type Filter func(Context) bool

func NewConditionalHandler(filter Filter, handlers ...Handler) Handler
```

Here is a usage example, which checks if a subdomain exists and it is NOT the `static.` one:

```go
app.UseRouter(iris.NewConditionalHandler(isNotStaticSubdomain, auth))
```

```go
func isNotStaticSubdomain(ctx iris.Context) bool {
    return ctx.Subdomain() != "static."
}
```

That's all. When you've got the idea, it's trivial.

## Transfer Data Between Handlers

Each request-response lifecycle contains an instance of `iris.Context`. This instance is shared across the handlers chain—the `Context.Values()` returns temporary memory storage which can be used to transfer data between middleware and handlers.

This storage contains many helper methods, the most important you'll probably use are:

```go
Set(key string, value interface{}) (Entry, bool)
Get(key string) interface{}
```

### Usage

**Set** a value:

```go
func myMiddleware(ctx iris.Context) {
    ctx.Values().Set("key", value)
}
```

**Get** a value:

```go
func myHandler(ctx iris.Context) {
    value := ctx.Values().Get("key")
}
```

[Complete list of the memstore methods](https://github.com/kataras/iris/blob/39e3911d4107ca741db9c23f514cf569f09f7168/core/memstore/memstore.go#L701-L1151).

## Writing a middleware

```go
package main

import "github.com/kataras/iris/v12"

func main() {
    app := iris.New()
    // or app.Use(before) and app.Done(after).
    app.Get("/", before, mainHandler, after)
    app.Listen(":8080")
}

func before(ctx iris.Context) {
    shareInformation := "this is a sharable information between handlers"

    requestPath := ctx.Path()
    println("Before the mainHandler: " + requestPath)

    ctx.Values().Set("info", shareInformation)
    ctx.Next() // execute the next handler, in this case the main one.
}

func after(ctx iris.Context) {
    println("After the mainHandler")
}

func mainHandler(ctx iris.Context) {
    println("Inside mainHandler")

    // take the info from the "before" handler.
    info := ctx.Values().GetString("info")

    // write something to the client as a response.
    ctx.HTML("<h1>Response</h1>")
    ctx.HTML("<br/> Info: " + info)

    ctx.Next() // execute the "after".
}
```

```bash
$ go run main.go # and navigate to the http://localhost:8080
Now listening on: http://localhost:8080
Application started. Press CTRL+C to shut down.
Before the mainHandler: /
Inside mainHandler
After the mainHandler
```

## Removing a Handler from a Route

To remove a specific handler from a specific route use the `RemoveHandler` method of the `*Route` registered by the `Handle/Get/Post/Put...` methods. The `RemoveHandler` method expects the handler name (it's the PC func, see `HandlerName` of the iris `context` subpackage) or the handler itself.

Example Code:

```go
func middleware(ctx iris.Context) {
    // [...]
}

func main() {
    app := iris.New()

    // Register the middleware to all matched routes.
    app.Use(middleware)

    // Handlers = middleware, other
    app.Get("/", index)

    // Handlers = other
    app.Get("/other", other).RemoveHandler(middleware)
}
```

## Execution Rules

You could also use the `ExecutionRules` to force Begin(UseXXX) and Finish(DoneXXX) handlers to be executed without the requirement of a `ctx.Next()` call, to forcibly forward them:

```go
app.SetExecutionRules(iris.ExecutionRules{
    // Begin: ...
    // Main:  ...
    Done: iris.ExecutionOptions{Force: true},
})
```

## Convert `http.Handler/HandlerFunc`

However, you are not limited to them - you can use any third-party middleware that works with the [net/http](https://pkg.go.dev/net/http/) package.

Iris, unlike others, is 100% compatible with the standards and that's why many big companies that use Go in their workflow, like a very famous US Television Network, trust Iris; it's up-to-date, and it will always follow the std `net/http` package which is updated by the Go Authors on each new release of the Go Programming Language.

You can use any third-party middleware that is written for `net/http` with Iris by using the `iris.FromStd(aThirdPartyMiddleware)`. Remember, `ctx.ResponseWriter()` and `ctx.Request()` return the same `net/http` input arguments of an [http.Handler](https://pkg.go.dev/net/http/#Handler).

* [From func(w http.ResponseWriter, r \*http.Request, next http.HandlerFunc)](https://github.com/kataras/iris/tree/main/_examples/convert-handlers/negroni-like/main.go)
* [From http.Handler or http.HandlerFunc](https://github.com/kataras/iris/tree/main/_examplesconvert-handlers/nethttp/main.go)
* [From func(http.HandlerFunc) http.HandlerFunc](https://github.com/kataras/iris/tree/main/_examplesconvert-handlers/real-usecase-raven/writing-middleware/main.go)

Here is a list of some handlers made specifically for Iris:

## Built-in

| Middleware                                                                                                | Example                                                                                                                                              |
| --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| [rewrite](https://github.com/kataras/iris-book/blob/master/routing/rewrite/README.md)                     | [iris/\_examples/routing/rewrite](https://github.com/kataras/iris/tree/main/_examples/routing/rewrite)                                               |
| [basic authentication](https://github.com/kataras/iris-book/blob/master/routing/basicauth/README.md)      | [iris/\_examples/auth/basicauth](https://github.com/kataras/iris/tree/main/_examples/auth/basicauth)                                                 |
| [request logger](https://github.com/kataras/iris-book/blob/master/routing/logger/README.md)               | [iris/\_examples/logging/request-logger](https://github.com/kataras/iris/tree/main/_examples/logging/request-logger)                                 |
| [HTTP method override](https://github.com/kataras/iris-book/blob/master/routing/methodoverride/README.md) | [iris/middleware/methodoverride/methodoverride\_test.go](https://github.com/kataras/iris/blob/main/middleware/methodoverride/methodoverride_test.go) |
| [profiling (pprof)](https://github.com/kataras/iris-book/blob/master/routing/pprof/README.md)             | [iris/\_examples/pprof](https://github.com/kataras/iris/tree/main/_examples/pprof)                                                                   |
| [Google reCAPTCHA](https://github.com/kataras/iris-book/blob/master/routing/recaptcha/README.md)          | [iris/\_examples/auth/recaptcha](https://github.com/kataras/iris/tree/main/_examples/auth/recaptcha)                                                 |
| [hCaptcha](https://github.com/kataras/iris-book/blob/master/routing/hcaptcha/README.md)                   | [iris/\_examples/auth/recaptcha](https://github.com/kataras/iris/tree/main/_examples/auth/hcaptcha)                                                  |
| [recovery](https://github.com/kataras/iris-book/blob/master/routing/recover/README.md)                    | [iris/\_examples/recover](https://github.com/kataras/iris/tree/main/_examples/recover)                                                               |
| [rate](https://github.com/kataras/iris-book/blob/master/routing/rate/README.md)                           | [iris/\_examples/request-ratelimit](https://github.com/kataras/iris/tree/main/_examples/request-ratelimit)                                           |
| [jwt](https://github.com/kataras/iris-book/blob/master/routing/jwt/README.md)                             | [iris/\_examples/auth/jwt](https://github.com/kataras/iris/tree/main/_examples/auth/jwt)                                                             |
| [requestid](https://github.com/kataras/iris-book/blob/master/routing/requestid/README.md)                 | [iris/middleware/requestid/requestid\_test.go](https://github.com/kataras/iris/blob/main/_examples/middleware/requestid/requestid_test.go)           |

## Community

| Middleware                                                                       | Description                                                                                    | Example                                                                                                                                                    |
| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [pg](https://github.com/iris-contrib/middleware/tree/master/pg)                  | Middleware that provides easy and type-safe access to PostgreSQL database                      | [iris-contrib/middleware/pg/\_examples](https://github.com/iris-contrib/middleware/tree/master/pg/_examples)                                               |
| [jwt](https://github.com/iris-contrib/middleware/tree/master/jwt)                | Middleware checks for a JWT on the `Authorization` header on incoming requests and decodes it  | [iris-contrib/middleware/jwt/\_example](https://github.com/iris-contrib/middleware/tree/master/jwt/_example)                                               |
| [cors](https://github.com/iris-contrib/middleware/tree/master/cors)              | HTTP Access Control                                                                            | [iris-contrib/middleware/cors/\_example](https://github.com/iris-contrib/middleware/tree/master/cors/_example)                                             |
| [secure](https://github.com/iris-contrib/middleware/tree/master/secure)          | Middleware that implements a few quick security wins                                           | [iris-contrib/middleware/secure/\_example](https://github.com/iris-contrib/middleware/tree/master/secure/_example/main.go)                                 |
| [tollbooth](https://github.com/iris-contrib/middleware/tree/master/tollboothic)  | Generic middleware to rate-limit HTTP requests                                                 | [iris-contrib/middleware/tollboothic/\_examples/limit-handler](https://github.com/iris-contrib/middleware/tree/master/tollboothic/_examples/limit-handler) |
| [cloudwatch](https://github.com/iris-contrib/middleware/tree/master/cloudwatch)  | AWS cloudwatch metrics middleware                                                              | [iris-contrib/middleware/cloudwatch/\_example](https://github.com/iris-contrib/middleware/tree/master/cloudwatch/_example)                                 |
| [new relic](https://github.com/iris-contrib/middleware/tree/master/newrelic)     | Official [New Relic Go Agent](https://github.com/newrelic/go-agent)                            | [iris-contrib/middleware/newrelic/\_example](https://github.com/iris-contrib/middleware/tree/master/newrelic/_example)                                     |
| [prometheus](https://github.com/iris-contrib/middleware/tree/master/prometheus)  | Easily create metrics endpoint for the [prometheus](http://prometheus.io) instrumentation tool | [iris-contrib/middleware/prometheus/\_example](https://github.com/iris-contrib/middleware/tree/master/prometheus/_example)                                 |
| [casbin](https://github.com/iris-contrib/middleware/tree/master/casbin)          | An authorization library that supports access control models like ACL, RBAC, ABAC              | [iris-contrib/middleware/casbin/\_examples](https://github.com/iris-contrib/middleware/tree/master/casbin/_examples)                                       |
| [sentry-go (ex. raven)](https://github.com/getsentry/sentry-go/tree/master/iris) | Sentry client in Go                                                                            | [sentry-go/example/iris](https://github.com/getsentry/sentry-go/blob/master/example/iris/main.go)                                                          |
| [csrf](https://github.com/iris-contrib/middleware/tree/master/csrf)              | Cross-Site Request Forgery Protection                                                          | [iris-contrib/middleware/csrf/\_example](https://github.com/iris-contrib/middleware/blob/master/csrf/_example/main.go)                                     |
| [throttler](https://github.com/iris-contrib/middleware/tree/master/throttler)    | Rate limiting access to HTTP endpoints                                                         | [iris-contrib/middleware/throttler/\_example](https://github.com/iris-contrib/middleware/blob/master/throttler/_example/main.go)                           |

## Third-Party

Iris has its own middleware form of `func(ctx iris.Context)`, but it's also compatible with all `net/http` middleware forms. See [here](https://github.com/kataras/iris/tree/main/_examples/convert-handlers).

Here's a small list of useful third-party handlers:

| Middleware                                              | Description                                                                                                                     |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| [goth](https://github.com/markbates/goth)               | OAuth, OAuth2 authentication. [Example](https://github.com/kataras/iris/tree/main/_examples/auth/goth)                          |
| [permissions2](https://github.com/xyproto/permissions2) | Cookies, users and permissions. [Example](https://github.com/kataras/iris/tree/main/_examples/auth/permissions)                 |
| [csp](https://github.com/awakenetworks/csp)             | [Content Security Policy](https://www.w3.org/TR/CSP2/) (CSP) support                                                            |
| [delay](https://github.com/jeffbmartinez/delay)         | Add delays/latency to endpoints. Useful when testing effects of high latency                                                    |
| [onthefly](https://github.com/xyproto/onthefly)         | Generate TinySVG, HTML and CSS on the fly                                                                                       |
| [RestGate](https://github.com/pjebs/restgate)           | Secure authentication for REST API endpoints                                                                                    |
| [stats](https://github.com/thoas/stats)                 | Store information about your web application (response time, etc.)                                                              |
| [VanGoH](https://github.com/auroratechnologies/vangoh)  | Configurable [AWS-Style](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html) HMAC authentication middleware |
| [digits](https://github.com/bamarni/digits)             | Middleware that handles [Twitter Digits](https://get.digits.com/) authentication                                                |


---

# 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/routing/middleware.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.
