Click here to read about the versioning API that the most recent version of Iris brings to you.
Iris Web Framework
Iris is a fast, simple yet fully featured and very efficient web framework for Go.
Iris provides a beautifully expressive and easy to use foundation for your next website or API.
Iris offers a complete and decent solution and support for all gophers around the globe.
Learn what others say about Iris and star this github repository to stay up to date.
Installation
The only requirement is the Go Programming Language
$ go get -u github.com/kataras/iris
Iris takes advantage of the vendor directory feature. You get truly reproducible builds, as this method guards against upstream renames and deletes.
Known issues for code editors and IDEs at general
VS Code
For some reason the latest vscode-go language extension does not provide enough intelligence for the iris.Context
type alias (input parameters documentation and definition navigation).
Probably you have already experienced this issue with other Go libraries too, it is not an iris-specific issue, it is a general issue for all Golang type aliases.
Therefore if you use VS Code and you need these editor's features, import the original path; add an extra import statement of the original path of the Context
, that will do it:
import (
"github.com/kataras/iris"
"github.com/kataras/iris/context"
)
Benchmarks
Iris vs .NET Core vs Expressjs
Updated at: Monday, 22 October 2018
Iris vs the rest Go web frameworks and routers vs any other alternative
As shown in the benchmarks (from a third-party source), Iris is the fastest open-source Go web framework in the planet. The net/http 100% compatible router muxie I've created some weeks ago is also trending there with amazing results, fastest net/http router ever created as well. View the results at:
https://github.com/the-benchmarker/web-frameworks#full-table
Philosophy
The Iris philosophy is to provide robust tooling for HTTP, making it a great solution for single page applications, web sites, hybrids, or public HTTP APIs. Keep note that, so far, iris is the fastest web framework ever created in terms of performance.
Iris does not force you to use any specific ORM or template engine. With support for the most used template engines, you can quickly craft the perfect application.
Quick start
$ cat example.go
package main
import "github.com/kataras/iris"
func main() {
app := iris.Default()
app.Get("/ping", func(ctx iris.Context) {
ctx.JSON(iris.Map{
"message": "pong",
})
})
app.Run(iris.Addr(":8080"))
}
# run example.go and visit http://0.0.0.0:8080/ping on browser
$ go run example.go
Iris starter kits
- snowlyg/IrisApiProject: Iris + gorm + jwt + sqlite3 NEW-Chinese
- yz124/superstar: Iris + xorm to implement the star library NEW-Chinese
- jebzmos4/Iris-golang: A basic CRUD API in golang with Iris
- gauravtiwari/go_iris_app: A basic web app built in Iris for Go
- A mini social-network created with the awesome Iris💖💖
- Iris isomorphic react/hot reloadable/redux/css-modules starter kit
- ionutvilie/react-ts: Demo project with react using typescript and Iris
- Self-hosted Localization Management Platform built with Iris and Angular
- Iris + Docker and Kubernetes
- nanobox.io: Quickstart for Iris with Nanobox
- hasura.io: A Hasura starter project with a ready to deploy Golang hello-world web app with IRIS
Did you build something similar? Let us know!
API Examples
Using Get, Post, Put, Patch, Delete and Options
func main() {
app := iris.Default()
app.Get("/someGet", getting)
app.Post("/somePost", posting)
app.Put("/somePut", putting)
app.Delete("/someDelete", deleting)
app.Patch("/somePatch", patching)
app.Head("/someHead", head)
app.Options("/someOptions", options)
app.Run(iris.Addr(":8080"))
}
Parameters in path
Param Type | Go Type | Validation | Retrieve Helper |
---|
:string | string | anything (single path segment) | Params().Get |
:int | int | -9223372036854775808 to 9223372036854775807 (x64) or -2147483648 to 2147483647 (x32), depends on the host arch | Params().GetInt |
:int8 | int8 | -128 to 127 | Params().GetInt8 |
:int16 | int16 | -32768 to 32767 | Params().GetInt16 |
:int32 | int32 | -2147483648 to 2147483647 | Params().GetInt32 |
:int64 | int64 | -9223372036854775808 to 9223372036854775807 | Params().GetInt64 |
:uint | uint | 0 to 18446744073709551615 (x64) or 0 to 4294967295 (x32), depends on the host arch | Params().GetUint |
:uint8 | uint8 | 0 to 255 | Params().GetUint8 |
:uint16 | uint16 | 0 to 65535 | Params().GetUint16 |
:uint32 | uint32 | 0 to 4294967295 | Params().GetUint32 |
:uint64 | uint64 | 0 to 18446744073709551615 | Params().GetUint64 |
:bool | bool | "1" or "t" or "T" or "TRUE" or "true" or "True" or "0" or "f" or "F" or "FALSE" or "false" or "False" | Params().GetBool |
:alphabetical | string | lowercase or uppercase letters | Params().Get |
:file | string | lowercase or uppercase letters, numbers, underscore (_), dash (-), point (.) and no spaces or other special characters that are not valid for filenames | Params().Get |
:path | string | anything, can be separated by slashes (path segments) but should be the last part of the route path | Params().Get |
Usage:
app.Get("/users/{id:uint64}", func(ctx iris.Context){
id := ctx.Params().GetUint64Default("id", 0)
})
Built'n Func | Param Types |
---|
regexp (expr string) | :string |
prefix (prefix string) | :string |
suffix (suffix string) | :string |
contains (s string) | :string |
min (minValue int or int8 or int16 or int32 or int64 or uint8 or uint16 or uint32 or uint64 or float32 or float64) | :string(char length), :int, :int8, :int16, :int32, :int64, :uint, :uint8, :uint16, :uint32, :uint64 |
max (maxValue int or int8 or int16 or int32 or int64 or uint8 or uint16 or uint32 or uint64 or float32 or float64) | :string(char length), :int, :int8, :int16, :int32, :int64, :uint, :uint8, :uint16, :uint32, :uint64 |
range (minValue, maxValue int or int8 or int16 or int32 or int64 or uint8 or uint16 or uint32 or uint64 or float32 or float64) | :int, :int8, :int16, :int32, :int64, :uint, :uint8, :uint16, :uint32, :uint64 |
Usage:
app.Get("/profile/{name:alphabetical max(255)}", func(ctx iris.Context){
name := ctx.Params().Get("name")
})
Do It Yourself:
The RegisterFunc
can accept any function that returns a func(paramValue string) bool
.
Or just a func(string) bool
.
If the validation fails then it will fire 404
or whatever status code the else
keyword has.
latLonExpr := "^-?[0-9]{1,3}(?:\\.[0-9]{1,10})?$"
latLonRegex, _ := regexp.Compile(latLonExpr)
app.Macros().Get("string").RegisterFunc("coordinate", latLonRegex.MatchString)
app.Get("/coordinates/{lat:string coordinate()}/{lon:string coordinate()}", func(ctx iris.Context) {
ctx.Writef("Lat: %s | Lon: %s", ctx.Params().Get("lat"), ctx.Params().Get("lon"))
})
Register your custom macro function which accepts two int arguments.
app.Macros().Get("string").RegisterFunc("range", func(minLength, maxLength int) func(string) bool {
return func(paramValue string) bool {
return len(paramValue) >= minLength && len(paramValue) <= maxLength
}
})
app.Get("/limitchar/{name:string range(1,200) else 400}", func(ctx iris.Context) {
name := ctx.Params().Get("name")
ctx.Writef(`Hello %s | the name should be between 1 and 200 characters length
otherwise this handler will not be executed`, name)
})
Register your custom macro function which accepts a slice of strings [...,...]
.
app.Macros().Get("string").RegisterFunc("has", func(validNames []string) func(string) bool {
return func(paramValue string) bool {
for _, validName := range validNames {
if validName == paramValue {
return true
}
}
return false
}
})
app.Get("/static_validation/{name:string has([kataras,gerasimos,maropoulos])}", func(ctx iris.Context) {
name := ctx.Params().Get("name")
ctx.Writef(`Hello %s | the name should be "kataras" or "gerasimos" or "maropoulos"
otherwise this handler will not be executed`, name)
})
Example Code:
func main() {
app := iris.Default()
app.Get("/user/{name}", func(ctx iris.Context) {
name := ctx.Params().Get("name")
ctx.Writef("Hello %s", name)
})
app.Get("/users/{id:uint64}", func(ctx iris.Context) {
id := ctx.Params().GetUint64Default("id", 0)
ctx.Writef("User with ID: %d", id)
})
app.Post("/user/{name:string}/{action:path}", func(ctx iris.Context) {
name := ctx.Params().Get("name")
action := ctx.Params().Get("action")
message := name + " is " + action
ctx.WriteString(message)
})
app.Run(iris.Addr(":8080"))
}
If parameter type is missing then defaults to string
, therefore {name:string}
and {name}
do the same exactly thing.
Learn more about path parameter's types by navigating here.
Dependency Injection
The package hero contains features for binding any object or functions that handlers
can use, these are called dependencies.
With Iris you get truly safe bindings thanks to the hero package. It is blazing-fast, near to raw handlers performance because Iris calculates everything before even server goes online!
Below you will see some screenshots I prepared for you in order to be easier to understand:
1. Path Parameters - Built'n Dependencies
2. Services - Static Dependencies
3. Per-Request - Dynamic Dependencies
hero funcs
are very easy to understand and when you start using them you never go back.
With Iris you also get real and blazing-fast MVC support which uses "hero" under the hoods.
Querystring parameters
func main() {
app := iris.Default()
app.Get("/welcome", func(ctx iris.Context) {
firstname := ctx.URLParamDefault("firstname", "Guest")
lastname := ctx.URLParam("lastname")
ctx.Writef("Hello %s %s", firstname, lastname)
})
app.Run(iris.Addr(":8080"))
}
Multipart/Urlencoded Form
func main() {
app := iris.Default()
app.Post("/form_post", func(ctx iris.Context) {
message := ctx.FormValue("message")
nick := ctx.FormValueDefault("nick", "anonymous")
ctx.JSON(iris.Map{
"status": "posted",
"message": message,
"nick": nick,
})
})
app.Run(iris.Addr(":8080"))
}
Another example: query + post form
POST /post?id=1234&page=1 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
name=manu&message=this_is_great
func main() {
app := iris.Default()
app.Post("/post", func(ctx iris.Context) {
id := ctx.URLParam("id")
page := ctx.URLParamDefault("page", "0")
name := ctx.FormValue("name")
message := ctx.FormValue("message")
app.Logger().Infof("id: %s; page: %s; name: %s; message: %s", id, page, name, message)
})
app.Run(iris.Addr(":8080"))
}
id: 1234; page: 1; name: manu; message: this_is_great
package main
import (
"github.com/kataras/iris"
"github.com/kataras/iris/context"
)
func main() {
app := iris.New()
app.Get("/", func(ctx context.Context) {
r := ctx.GetReferrer()
switch r.Type {
case context.ReferrerSearch:
ctx.Writef("Search %s: %s\n", r.Label, r.Query)
ctx.Writef("Google: %s\n", r.GoogleType)
case context.ReferrerSocial:
ctx.Writef("Social %s\n", r.Label)
case context.ReferrerIndirect:
ctx.Writef("Indirect: %s\n", r.URL)
}
})
app.Run(iris.Addr(":8080"))
}
How to curl
:
curl http://localhost:8080?referer=https://twitter.com/Xinterio/status/1023566830974251008
curl http://localhost:8080?referer=https://www.google.com/search?q=Top+6+golang+web+frameworks&oq=Top+6+golang+web+frameworks
Upload files
const maxSize = 5 << 20
func main() {
app := iris.Default()
app.Post("/upload", iris.LimitRequestBodySize(maxSize), func(ctx iris.Context) {
ctx.UploadFormFiles("./uploads", beforeSave)
})
app.Run(iris.Addr(":8080"))
}
func beforeSave(ctx iris.Context, file *multipart.FileHeader) {
ip := ctx.RemoteAddr()
ip = strings.Replace(ip, ".", "_", -1)
ip = strings.Replace(ip, ":", "_", -1)
file.Filename = ip + "-" + file.Filename
}
How to curl
:
curl -X POST http://localhost:8080/upload \
-F "files[]=@./myfile.zip" \
-F "files[]=@./mysecondfile.zip" \
-H "Content-Type: multipart/form-data"
Grouping routes
func main() {
app := iris.Default()
v1 := app.Party("/v1")
{
v1.Post("/login", loginEndpoint)
v1.Post("/submit", submitEndpoint)
v1.Post("/read", readEndpoint)
}
v2 := app.Party("/v2")
{
v2.Post("/login", loginEndpoint)
v2.Post("/submit", submitEndpoint)
v2.Post("/read", readEndpoint)
}
app.Run(iris.Addr(":8080"))
}
Blank Iris without middleware by default
Use
app := iris.New()
instead of
app := iris.Default()
Using middleware
import (
"github.com/kataras/iris"
"github.com/kataras/iris/middleware/recover"
"github.com/kataras/iris/middleware/logger"
)
func main() {
app := iris.New()
app.Use(recover.New())
requestLogger := logger.New(logger.Config{
Status: true,
IP: true,
Method: true,
Path: true,
Query: true,
MessageContextKeys: []string{"logger_message"},
MessageHeaderKeys: []string{"User-Agent"},
})
app.Use(requestLogger)
app.Get("/benchmark", MyBenchLogger(), benchEndpoint)
authorized := app.Party("/user")
authorized.Use(AuthRequired())
{
authorized.Post("/login", loginEndpoint)
authorized.Post("/submit", submitEndpoint)
authorized.Post("/read", readEndpoint)
testing := authorized.Party("/testing")
testing.Get("/analytics", analyticsEndpoint)
}
app.Run(iris.Addr(":8080"))
}
How to write log file
package main
import (
"os"
"time"
"github.com/kataras/iris"
)
func todayFilename() string {
today := time.Now().Format("Jan 02 2006")
return today + ".txt"
}
func newLogFile() *os.File {
filename := todayFilename()
f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
panic(err)
}
return f
}
func main() {
f := newLogFile()
defer f.Close()
app := iris.New()
app.Logger().SetOutput(f)
app.Get("/ping", func(ctx iris.Context) {
ctx.Application().Logger().Infof("Request path: %s", ctx.Path())
ctx.WriteString("pong")
})
app.Run(
iris.Addr(":8080"),
iris.WithoutBanner,
iris.WithoutServerError(iris.ErrServerClosed),
)
}
Model binding and validation
Iris uses go-playground/validator.v9 for validation. Check the full docs on tags usage here.
Example detail code.
Note that you need to set the corresponding binding tag on all fields you want to bind. For example, when binding from JSON, set json:"fieldname"
.
package main
import (
"fmt"
"github.com/kataras/iris"
"gopkg.in/go-playground/validator.v9"
)
type User struct {
FirstName string `json:"fname"`
LastName string `json:"lname"`
Age uint8 `json:"age" validate:"gte=0,lte=130"`
Email string `json:"email" validate:"required,email"`
FavouriteColor string `json:"favColor" validate:"hexcolor|rgb|rgba"`
Addresses []*Address `json:"addresses" validate:"required,dive,required"`
}
type Address struct {
Street string `json:"street" validate:"required"`
City string `json:"city" validate:"required"`
Planet string `json:"planet" validate:"required"`
Phone string `json:"phone" validate:"required"`
}
var validate *validator.Validate
func main() {
validate = validator.New()
validate.RegisterStructValidation(UserStructLevelValidation, User{})
app := iris.New()
app.Post("/user", func(ctx iris.Context) {
var user User
if err := ctx.ReadJSON(&user); err != nil {
}
err := validate.Struct(user)
if err != nil {
if _, ok := err.(*validator.InvalidValidationError); ok {
ctx.StatusCode(iris.StatusInternalServerError)
ctx.WriteString(err.Error())
return
}
ctx.StatusCode(iris.StatusBadRequest)
for _, err := range err.(validator.ValidationErrors) {
fmt.Println()
fmt.Println(err.Namespace())
fmt.Println(err.Field())
fmt.Println(err.StructNamespace())
fmt.Println(err.StructField())
fmt.Println(err.Tag())
fmt.Println(err.ActualTag())
fmt.Println(err.Kind())
fmt.Println(err.Type())
fmt.Println(err.Value())
fmt.Println(err.Param())
fmt.Println()
}
return
}
})
app.Run(iris.Addr(":8080"))
}
func UserStructLevelValidation(sl validator.StructLevel) {
user := sl.Current().Interface().(User)
if len(user.FirstName) == 0 && len(user.LastName) == 0 {
sl.ReportError(user.FirstName, "FirstName", "fname", "fnameorlname", "")
sl.ReportError(user.LastName, "LastName", "lname", "fnameorlname", "")
}
}
{
"fname": "",
"lname": "",
"age": 45,
"email": "mail@example.com",
"favColor": "#000",
"addresses": [{
"street": "Eavesdown Docks",
"planet": "Persphone",
"phone": "none",
"city": "Unknown"
}]
}
Websockets
package main
import (
"fmt"
"github.com/kataras/iris"
"github.com/kataras/iris/websocket"
)
func main() {
app := iris.New()
app.Get("/", func(ctx iris.Context) {
ctx.ServeFile("websockets.html", false)
})
setupWebsocket(app)
app.Run(iris.Addr(":8080"))
}
func setupWebsocket(app *iris.Application) {
ws := websocket.New(websocket.Config{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
})
ws.OnConnection(handleConnection)
app.Get("/echo", ws.Handler())
app.Any("/iris-ws.js", websocket.ClientHandler())
}
func handleConnection(c websocket.Connection) {
c.On("chat", func(msg string) {
fmt.Printf("%s sent: %s\n", c.Context().RemoteAddr(), msg)
c.To(websocket.Broadcast).Emit("chat", msg)
})
}
websockets.html
<input id="input" type="text" />
<button onclick="send()">Send</button>
<pre id="output"></pre>
<script src="/iris-ws.js"></script>
<script>
var scheme = document.location.protocol == "https:" ? "wss" : "ws";
var port = document.location.port ? (":" + document.location.port) : "";
var wsURL = scheme + "://" + document.location.hostname + port+"/echo";
var input = document.getElementById("input");
var output = document.getElementById("output");
var socket = new Ws(wsURL)
socket.OnConnect(function () {
output.innerHTML += "Status: Connected\n";
});
socket.OnDisconnect(function () {
output.innerHTML += "Status: Disconnected\n";
});
socket.On("chat", function (msg) {
addMessage(msg);
});
function send() {
addMessage("Me: " + input.value);
socket.Emit("chat", input.value);
input.value = "";
}
function addMessage(msg) {
output.innerHTML += msg + "\n";
}
</script>
Navigate to the _examples/websocket folder for more.
Cookies
Are you looking about http sessions instead?
Let's write a simple application which will make use of the HTTP Cookies.
$ cat _examples/cookies/basic/main.go
package main
import "github.com/kataras/iris"
func newApp() *iris.Application {
app := iris.New()
app.Get("/cookies/{name}/{value}", func(ctx iris.Context) {
name := ctx.Params().Get("name")
value := ctx.Params().Get("value")
ctx.SetCookieKV(name, value)
ctx.Writef("cookie added: %s = %s", name, value)
})
app.Get("/cookies/{name}", func(ctx iris.Context) {
name := ctx.Params().Get("name")
value := ctx.GetCookie(name)
ctx.WriteString(value)
})
app.Delete("/cookies/{name}", func(ctx iris.Context) {
name := ctx.Params().Get("name")
ctx.RemoveCookie(name)
ctx.Writef("cookie %s removed", name)
})
return app
}
func main() {
app := newApp()
app.Run(iris.Addr(":8080"))
}
- Alternatively, use a regular
http.Cookie
: ctx.SetCookie(&http.Cookie{...})
- If you want to set custom the path:
ctx.SetCookieKV(name, value, iris.CookiePath("/custom/path/cookie/will/be/stored"))
. - If you want to be available only to the current request path:
ctx.SetCookieKV(name, value, iris.CookieCleanPath /* or iris.CookiePath("") */)
iris.CookieExpires(time.Duration)
iris.CookieHTTPOnly(false)
ctx.Request().Cookie(name)
is also available, it's the net/http
approach- Learn more about path parameter's types by clicking here.
Testing
Iris offers an incredible support for the httpexpect, a Testing Framework for web applications. However, you are able to use the standard Go's net/http/httptest
package as well but in this example we will use the kataras/iris/httptest
.
package main
import (
"fmt"
"testing"
"github.com/kataras/iris/httptest"
)
func TestCookiesBasic(t *testing.T) {
app := newApp()
e := httptest.New(t, app, httptest.URL("http://example.com"))
cookieName, cookieValue := "my_cookie_name", "my_cookie_value"
t1 := e.GET(fmt.Sprintf("/cookies/%s/%s", cookieName, cookieValue)).Expect().Status(httptest.StatusOK)
t1.Cookie(cookieName).Value().Equal(cookieValue)
t1.Body().Contains(cookieValue)
path := fmt.Sprintf("/cookies/%s", cookieName)
t2 := e.GET(path).Expect().Status(httptest.StatusOK)
t2.Body().Equal(cookieValue)
t3 := e.DELETE(path).Expect().Status(httptest.StatusOK)
t3.Body().Contains(cookieName)
t4 := e.GET(path).Expect().Status(httptest.StatusOK)
t4.Cookies().Empty()
t4.Body().Empty()
}
Learn
First of all, the most correct way to begin with a web framework is to learn the basics of the programming language and the standard http
capabilities, if your web application is a very simple personal project without performance and maintainability requirements you may want to proceed just with the standard packages. After that follow the guidelines:
Middleware
Iris has a great collection of handlers[1][2] that you can use side by side with your web apps. However you are not limited to them - you are free to use any third-party middleware that is compatible with the net/http package, _examples/convert-handlers will show you the way.
Iris, unlike others, is 100% compatible with the standards and that's why the majority of the big companies that adapt Go to their workflow, like a very famous US Television Network, trust Iris; it's up-to-date and it will be always aligned with the std net/http
package which is modernized by the Go Authors on each new release of the Go Programming Language.
Articles
Video Courses
- Daily Coding - Web Framework Golang: Iris Framework by WarnabiruTV, source: youtube, cost: FREE
- Tutorial Golang MVC dengan Iris Framework & Mongo DB (19 parts so far) by Musobar Media, source: youtube, cost: FREE
- Go/Golang 27 - Iris framework : Routage de base by stephgdesign, source: youtube, cost: FREE
- Go/Golang 28 - Iris framework : Templating by stephgdesignn, source: youtube, cost: FREE
- Go/Golang 29 - Iris framework : Paramètres by stephgdesign, source: youtube, cost: FREE
- Go/Golang 30 - Iris framework : Les middelwares by stephgdesign, source: youtube, cost: FREE
- Go/Golang 31 - Iris framework : Les sessions by stephgdesign, source: youtube, cost: FREE
Support
- HISTORY file is your best friend, it contains information about the latest features and changes
- Did you happen to find a bug? Post it at github issues
- Do you have any questions or need to speak with someone experienced to solve a problem at real-time? Join us to the community chat
- Complete our form-based user experience report by clicking here
- Do you like the framework? Tweet something about it! The People have spoken:
Get hired
There are many companies and start-ups looking for Go web developers with Iris experience as requirement, we are searching for you every day and we post those information via our facebook page, like the page to get notified, we have already posted some of them.
Backers
Thank you to all our backers! 🙏 Become a backer
For more information about contributing to the Iris project please check the CONTRIBUTING.md file.
List of all Contributors
License
Iris is licensed under the 3-Clause BSD License. Iris is 100% free and open-source software.
For any questions regarding the license please send e-mail.