// Returning signals that the request is finished;
// it is not valid to use the Context after or
// concurrently with the completion of the Handler call.
//
// Depending on the HTTP client software, HTTP protocol version,
// and any intermediaries between the client and the iris server,
// it may not be possible to read from the
// Context.Request().Body after writing to the context.ResponseWriter().
// Cautious handlers should read the Context.Request().Body first, and then reply.
//
// Except for reading the body, handlers should not modify the provided Context.
//
// If Handler panics, the server (the caller of Handler) assumes that
// the effect of the panic was isolated to the active request.
// It recovers the panic, logs a stack trace to the server error log
// and hangs up the connection.
type Handler func(Context)
```
Once the handler is registered, we can use the returned [`Route`](https://godoc.org/github.com/kataras/iris/core/router#Route) instance to give a name to the handler registration for easier lookup in code or in templates.
For more information, checkout the [Routing and reverse lookups](routing_reverse.md) section.
## API
All HTTP methods are supported, developers can also register handlers for same paths for different methods.
The first parameter is the HTTP Method,
second parameter is the request path of the route,
third variadic parameter should contains one or more iris.Handler executed
by the registered order when a user requests for that specific resouce path from the server.
> `id:int` is a (typed) dynamic path parameter, learn more by scrolling down.
# Dynamic Path Parameters
Iris has the easiest and the most powerful routing process you have ever meet.
At the same time,
Iris has its own interpeter(yes like a programming language)
for route's path syntax and their dynamic path parameters parsing and evaluation.
We call them "macros" for shortcut.
How? It calculates its needs and if not any special regexp needed then it just
registers the route with the low-level path syntax,
otherwise it pre-compiles the regexp and adds the necessary middleware(s). That means that you have zero performance cost compared to other routers or web frameworks.
Standard macro types for route path parameters
```sh
+------------------------+
| {param:string} |
+------------------------+
string type
anything
+------------------------+
| {param:int} |
+------------------------+
int type
only numbers (0-9)
+------------------------+
| {param:long} |
+------------------------+
int64 type
only numbers (0-9)
+------------------------+
| {param:boolean} |
+------------------------+
bool type
only "1" or "t" or "T" or "TRUE" or "true" or "True"
or "0" or "f" or "F" or "FALSE" or "false" or "False"
+------------------------+
| {param:alphabetical} |
+------------------------+
alphabetical/letter type
letters only (upper or lowercase)
+------------------------+
| {param:file} |
+------------------------+
file type
letters (upper or lowercase)
numbers (0-9)
underscore (_)
dash (-)
point (.)
no spaces ! or other character
+------------------------+
| {param:path} |
+------------------------+
path type
anything, should be the last part, more than one path segment,
// -> true means valid, false means invalid fire 404 or if "else 500" is appended to the macro syntax then internal server error.
})
```
At the `func(argument ...)` you can have any standard type, it will be validated before the server starts so don't care about any performance cost there, the only thing it runs at serve time is the returning `func(paramValue string) bool`.
```go
{param:string equal(iris)} , "iris" will be the argument here:
ctx.Writef("path type accepts any number of path segments, path after /myfiles/ is: %s", ctx.Params().Get("directory"))
})
app.Run(iris.Addr(":8080"))
}
```
A **path parameter name should contain only alphabetical letters. Symbols like '_' and numbers are NOT allowed**.
Last, do not confuse `ctx.Params()` with `ctx.Values()`.
Path parameter's values goes to `ctx.Params()` and context's local storage
that can be used to communicate between handlers and middleware(s) goes to
`ctx.Values()`.
# Routing and reverse lookups
As mentioned in the [Handlers](handlers.md) chapter, Iris provides several handler registration methods, each of which returns a [`Route`](https://godoc.org/github.com/kataras/iris/core/router#Route) instance.
## Route naming
Route naming is easy, since we just call the returned `*Route` with a `Name` field to define a name:
```go
package main
import (
"github.com/kataras/iris"
)
func main() {
app := iris.New()
// define a function
h := func(ctx iris.Context) {
ctx.HTML("<b>Hi</b1>")
}
// handler registration and naming
home := app.Get("/", h)
home.Name = "home"
// or
app.Get("/about", h).Name = "about"
app.Get("/page/{id}", h).Name = "page"
app.Run(iris.Addr(":8080"))
}
```
## Route reversing AKA generating URLs from the route name
When we register the handlers for a specific path, we get the ability to create URLs based on the structured data we pass to Iris. In the example above, we've named three routers, one of which even takes parameters. If we're using the default `html/template` view engine, we can use a simple action to reverse the routes (and generae actual URLs):
```sh
Home: {{ urlpath "home" }}
About: {{ urlpath "about" }}
Page 17: {{ urlpath "page" "17" }}
```
Above code would generate the following output:
```sh
Home: http://localhost:8080/
About: http://localhost:8080/about
Page 17: http://localhost:8080/page/17
```
## Using route names in code
We can use the following methods/functions to work with named routes (and their parameters):
* [`GetRoutes`](https://godoc.org/github.com/kataras/iris/core/router#APIBuilder.GetRoutes) function to get all registered routes
* [`GetRoute(routeName string)`](https://godoc.org/github.com/kataras/iris/core/router#APIBuilder.GetRoute) method to retrieve a route by name
* [`URL(routeName string, paramValues ...interface{})`](https://godoc.org/github.com/kataras/iris/core/router#RoutePathReverser.URL) method to generate url string based on supplied parameters
* [`Path(routeName string, paramValues ...interface{}`](https://godoc.org/github.com/kataras/iris/core/router#RoutePathReverser.Path) method to generate just the path (without host and protocol) portion of the URL based on provided values
## Examples
Check out the [https://github.com/kataras/iris/tree/master/_examples/view/template_html_4](https://github.com/kataras/iris/tree/master/_examples/view/template_html_4) example for more details.
# Middleware
When we talk about Middleware in Iris we're talking about running code before and/or after our main handler code in a HTTP request lifecycle. For example, logging middleware might write the incoming request details to a log, then call the handler code, before writing details about the response to the log. One of the cool things about middleware is that these units are extremely flexible and reusable.
A middleware is just a **Handler** form of `func(ctx iris.Context)`, the middleware is being executed when the previous middleware calls the `ctx.Next()`, this can be used for authentication, i.e: if logged in then `ctx.Next()` otherwise fire an error response.
**Very rare**, you may never need that but it's here in any case you need it.
There are times you need to override or decide whether the Router will be executed on an incoming request. If you've any previous experience with the `net/http` and other web frameworks this function will be familiar with you (it has the form of a net/http middleware, but instead of accepting the next handler it accepts the Router as a function to be executed or not).
```go
// WrapperFunc is used as an expected input parameter signature
// for the WrapRouter. It's a "low-level" signature which is compatible
// with the net/http.
// It's being used to run or no run the router based on a custom logic.
type WrapperFunc func(w http.ResponseWriter, r *http.Request, firstNextIsTheRouter http.HandlerFunc)
// WrapRouter adds a wrapper on the top of the main router.
// Usually it's useful for third-party middleware
// when need to wrap the entire application with a middleware like CORS.
//
// Developers can add more than one wrappers,
// those wrappers' execution comes from last to first.
// That means that the second wrapper will wrap the first, and so on.
//
// Before build.
func WrapRouter(wrapperFunc WrapperFunc)
```
Iris' router searches for its routes based on the `HTTP Method` a Router Wrapper can override that behavior and execute custom code.
Example Code:
```go
package main
import (
"net/http"
"strings"
"github.com/kataras/iris"
)
// In this example you'll just see one use case of .WrapRouter.
// You can use the .WrapRouter to add custom logic when or when not the router should
// be executed in order to execute the registered routes' handlers.
//
// To see how you can serve files on root "/" without a custom wrapper
// just navigate to the "file-server/single-page-application" example.
//
// This is just for the proof of concept, you can skip this tutorial if it's too much for you.
There is not much to say here, it's just a function wrapper which accepts the native response writer and request and the next handler which is the Iris' Router itself, it's being or not executed whether is called or not, **it's a middleware for the whole Router**.
# Error handlers
You can define your own handlers when a specific http error code occurs.
> Error codes are the http status codes that are bigger or equal to 400, like 404 not found and 500 internal server.
// when 404 then render the template $views_dir/errors/404.html
ctx.View("errors/404.html")
}
func internalServerError(ctx iris.Context) {
ctx.WriteString("Oups something went wrong, try again")
}
func index(ctx context.Context) {
ctx.View("index.html")
}
```
# Context Outline
The `iris.Context` source code can be found [here](https://github.com/kataras/iris/blob/master/context/context.go). Keep note using an IDE/Editors with `auto-complete` feature will help you a lot.
```go
// Context is the midle-man server's "object" for the clients.
//
// A New context is being acquired from a sync.Pool on each connection.
// The Context is the most important thing on the iris's http flow.
//
// Developers send responses to the client's request through a Context.
// Developers get request information from the client's request a Context.
//
// This context is an implementation of the context.Context sub-package.
// context.Context is very extensible and developers can override
// its methods if that is actually needed.
type Context interface {
// ResponseWriter returns an http.ResponseWriter compatible response writer, as expected.
ResponseWriter() ResponseWriter
// ResetResponseWriter should change or upgrade the Context's ResponseWriter.
ResetResponseWriter(ResponseWriter)
// Request returns the original *http.Request, as expected.
Request() *http.Request
// SetCurrentRouteName sets the route's name internally,
// in order to be able to find the correct current "read-only" Route when
// end-developer calls the `GetCurrentRoute()` function.
// It's being initialized by the Router, if you change that name
// manually nothing really happens except that you'll get other
// route via `GetCurrentRoute()`.
// Instead, to execute a different path
// from this context you should use the `Exec` function
// or change the handlers via `SetHandlers/AddHandler` functions.
SetCurrentRouteName(currentRouteName string)
// GetCurrentRoute returns the current registered "read-only" route that
// was being registered to this request's path.
GetCurrentRoute() RouteReadOnly
// AddHandler can add handler(s)
// to the current request in serve-time,
// these handlers are not persistenced to the router.
//
// Router is calling this function to add the route's handler.
// If AddHandler called then the handlers will be inserted
// to the end of the already-defined route's handler.
//
AddHandler(...Handler)
// SetHandlers replaces all handlers with the new.
SetHandlers(Handlers)
// Handlers keeps tracking of the current handlers.
Handlers() Handlers
// HandlerIndex sets the current index of the
// current context's handlers chain.
// If -1 passed then it just returns the
// current handler index without change the current index.rns that index, useless return value.
//
// Look Handlers(), Next() and StopExecution() too.
HandlerIndex(n int) (currentIndex int)
// HandlerName returns the current handler's name, helpful for debugging.
HandlerName() string
// Next calls all the next handler from the handlers chain,
// it should be used inside a middleware.
//
// Note: Custom context should override this method in order to be able to pass its own context.Context implementation.
Next()
// NextHandler returns(but it is NOT executes) the next handler from the handlers chain.
//
// Use .Skip() to skip this handler if needed to execute the next of this returning handler.
NextHandler() Handler
// Skip skips/ignores the next handler from the handlers chain,
// it should be used inside a middleware.
Skip()
// StopExecution if called then the following .Next calls are ignored.
StopExecution()
// IsStopped checks and returns true if the current position of the Context is 255,