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 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, Party.Use, Party.UseOnce, Application.UseGlobal, Party.Done, Application.DoneGlobal, Party.UseRouter and Application.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.
The Application.WrapRouter
Method
Application.WrapRouter
MethodA 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
Party.UseRouter
MethodA 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
Application.UseGlobal
MethodA 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
Party.Use
MethodA 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
Party.UseError
MethodA 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
Party.Done
MethodRegister 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 are modified.
The Application.DoneGlobal
Method
Application.DoneGlobal
MethodSame 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:
Run our simple application:
Point your browser to http://localhost:8080
, and the output should look exactly like this:
And for a page that should give a 404, such as http://localhost:8080/a_not_found_resource
:
(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.
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:
And the second way is by using the iris.NewConditionalHandler:
Here is a usage example, which checks if a subdomain exists and it is NOT the static.
one:
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:
Usage
Set a value:
Get a value:
Complete list of the memstore methods.
Writing a middleware
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:
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:
Convert http.Handler/HandlerFunc
http.Handler/HandlerFunc
However, you are not limited to them - you can use any third-party middleware that works with the 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.
Here is a list of some handlers made specifically for Iris:
Built-in
Middleware | Example |
---|---|
Community
Middleware | Description | Example |
---|---|---|
Middleware that provides easy and type-safe access to PostgreSQL database | ||
Middleware checks for a JWT on the | ||
HTTP Access Control | ||
Middleware that implements a few quick security wins | ||
Generic middleware to rate-limit HTTP requests | ||
AWS cloudwatch metrics middleware | ||
Official New Relic Go Agent | ||
Easily create metrics endpoint for the prometheus instrumentation tool | ||
An authorization library that supports access control models like ACL, RBAC, ABAC | ||
Sentry client in Go | ||
Cross-Site Request Forgery Protection | ||
Rate limiting access to HTTP endpoints |
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.
Here's a small list of useful third-party handlers:
Middleware | Description |
---|---|
OAuth, OAuth2 authentication. Example | |
Cookies, users and permissions. Example | |
Content Security Policy (CSP) support | |
Add delays/latency to endpoints. Useful when testing effects of high latency | |
Generate TinySVG, HTML and CSS on the fly | |
Secure authentication for REST API endpoints | |
Store information about your web application (response time, etc.) | |
Configurable AWS-Style HMAC authentication middleware | |
Middleware that handles Twitter Digits authentication |
Last updated