Start

First of all, the 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:

  1. Read this page to learn how to install and use the Iris go package
  2. Navigate through 100+1 examples we crafted for you
  3. Read the godocs for any details
  4. Prepare a cup of coffee or tea, whatever pleases you the most, and read some articles we found for you
  5. Run some of our starter kits.

Table Of Contents

    Installation

    Note: Assuming that you have already installed Google Go. If not please follow installation guide.

    • go get github.com/kataras/iris@master
    • _

    Quick start

    # assume the following code in example.go file
    $ cat example.go
    
    package main
    
    import (
    	"github.com/kataras/iris"
    
    	"github.com/kataras/iris/middleware/logger"
    	"github.com/kataras/iris/middleware/recover"
    )
    
    func main() {
    	app := iris.New()
    	app.Logger().SetLevel("debug")
    	// Optionally, add two built'n handlers
    	// that can recover from any http-relative panics
    	// and log the requests to the terminal.
    	app.Use(recover.New())
    	app.Use(logger.New())
    
    	// Method:   GET
    	// Resource: http://localhost:8080
    	app.Handle("GET", "/", func(ctx iris.Context) {
    		ctx.HTML("<h1>Welcome</h1>")
    	})
    
    	// same as app.Handle("GET", "/ping", [...])
    	// Method:   GET
    	// Resource: http://localhost:8080/ping
    	app.Get("/ping", func(ctx iris.Context) {
    		ctx.WriteString("pong")
    	})
    
    	// Method:   GET
    	// Resource: http://localhost:8080/hello
    	app.Get("/hello", func(ctx iris.Context) {
    		ctx.JSON(iris.Map{"message": "Hello Iris!"})
    	})
    
    	// http://localhost:8080
    	// http://localhost:8080/ping
    	// http://localhost:8080/hello
    	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
    }

    Time to run your server, so just type go run example.go

    • go run example.go
    • Now listening on: http://localhost:8080
      Application started. Press CTRL+C to shut down.
      _

    API Examples

    Using Get, Post, Put, Patch, Delete and Options

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    func main() {
        // Creates an application with default middleware:
        // logger and recovery (crash-free) middleware.
        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 TypeTypeValidationRetrieve Helper
    :stringstringanything (single path segment)Params().Get
    :intint-9223372036854775808 to 9223372036854775807 (x64) or -2147483648 to 2147483647 (x32), depends on the host archParams().GetInt
    :int8int8-128 to 127Params().GetInt8
    :int16int16-32768 to 32767Params().GetInt16
    :int32int32-2147483648 to 2147483647Params().GetInt32
    :int64int64-9223372036854775808 to 9223372036854775807Params().GetInt64
    :uintuint0 to 18446744073709551615 (x64) or 0 to 4294967295 (x32), depends on the host archParams().GetUint
    :uint8uint80 to 255Params().GetUint8
    :uint16uint160 to 65535Params().GetUint16
    :uint32uint320 to 4294967295Params().GetUint32
    :uint64uint640 to 18446744073709551615Params().GetUint64
    :boolbool“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
    :alphabeticalstringlowercase or uppercase lettersParams().Get
    :filestringlowercase or uppercase letters, numbers, underscore (_), dash (-), point (.) and no spaces or other special characters that are not valid for filenamesParams().Get
    :pathstringanything, can be separated by slashes (path segments) but should be the last part of the route pathParams().Get


    Usage:

    1
    2
    3
    4
    
    app.Get("/users/{id:uint64}", func(ctx iris.Context){
        id := ctx.Params().GetUint64Default("id", 0)
        // [...]
    })


    Built-in FuncParam 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:

    1
    2
    3
    4
    5
    
    app.Get("/profile/{name:alphabetical max(255)}", func(ctx iris.Context){
        name := ctx.Params().Get("name")
        // len(name) <=255 otherwise this route will fire 404 Not Found
        // and this handler will not be executed at all.
    })


    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.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    latLonExpr := "^-?[0-9]{1,3}(?:\\.[0-9]{1,10})?$"
    latLonRegex, _ := regexp.Compile(latLonExpr)
    
    // Register your custom argument-less macro function to the :string param type.
    // MatchString is a type of func(string) bool, so we use it as it is.
    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.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    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 [...,...].

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    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:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    func main() {
        app := iris.Default()
    
        // This handler will match /user/john but will not match neither /user/ or /user.
        app.Get("/user/{name}", func(ctx iris.Context) {
            name := ctx.Params().Get("name")
            ctx.Writef("Hello %s", name)
        })
    
        // This handler will match /users/42
        // but will not match /users/-1 because uint should be bigger than zero
        // neither /users or /users/.
        app.Get("/users/{id:uint64}", func(ctx iris.Context) {
            id := ctx.Params().GetUint64Default("id", 0)
            ctx.Writef("User with ID: %d", id)
        })
    
        // However, this one will match /user/john/send and also /user/john/everything/else/here
        // but will not match /user/john neither /user/john/.
        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 the server even goes online!

    Below you will see some screenshots I prepared to facilitate understanding:

    1. Path Parameters - Built-in 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

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    func main() {
        app := iris.Default()
    
        // Query string parameters are parsed using the existing underlying request object.
        // The request responds to a url matching:  /welcome?firstname=Jane&lastname=Doe.
        app.Get("/welcome", func(ctx iris.Context) {
            firstname := ctx.URLParamDefault("firstname", "Guest")
            // shortcut for ctx.Request().URL.Query().Get("lastname").
            lastname := ctx.URLParam("lastname") 
    
            ctx.Writef("Hello %s %s", firstname, lastname)
        })
    
        app.Run(iris.Addr(":8080"))
    }

    Multipart/Urlencoded Form

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    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

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    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")
            // or `ctx.PostValue` for POST, PUT & PATCH-only HTTP Methods.
    
            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

    Extract Referer

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    package main
    
    import (
        "github.com/kataras/iris"
        "github.com/kataras/iris/context"
    )
    
    func main() {
        app := iris.New()
    
        app.Get("/", func(ctx context.Context) /* or iris.Context, it's the same for Go 1.9+. */ {
    
            // request header "referer" or url parameter "referer".
            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

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    
    const maxSize = 5 << 20 // 5MB
    
    func main() {
        app := iris.Default()
        app.Post("/upload", iris.LimitRequestBodySize(maxSize), func(ctx iris.Context) {
            //
            // UploadFormFiles
            // uploads any number of incoming files ("multiple" property on the form input).
            //
    
            // The second, optional, argument
            // can be used to change a file's name based on the request,
            // at this example we will showcase how to use it
            // by prefixing the uploaded file with the current user's ip.
            ctx.UploadFormFiles("./uploads", beforeSave)
        })
    
        app.Run(iris.Addr(":8080"))
    }
    
    func beforeSave(ctx iris.Context, file *multipart.FileHeader) {
        ip := ctx.RemoteAddr()
        // make sure you format the ip in a way
        // that can be used for a file name (simple case):
        ip = strings.Replace(ip, ".", "_", -1)
        ip = strings.Replace(ip, ":", "_", -1)
    
        // you can use the time.Now, to prefix or suffix the files
        // based on the current time as well, as an exercise.
        // i.e unixTime :=	time.Now().Unix()
        // prefix the Filename with the $IP-
        // no need for more actions, internal uploader will use this
        // name to save the file into the "./uploads" folder.
        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

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    func main() {
    	app := iris.Default()
    
    	// Simple group: v1.
    	v1 := app.Party("/v1")
    	{
    		v1.Post("/login", loginEndpoint)
    		v1.Post("/submit", submitEndpoint)
    		v1.Post("/read", readEndpoint)
    	}
    
    	// Simple group: v2.
    	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

    // Default with the Logger and Recovery middleware already attached.
    app := iris.Default()

    Using middleware

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    
    import (
        "github.com/kataras/iris"
    
        "github.com/kataras/iris/middleware/recover"
        "github.com/kataras/iris/middleware/logger"
    )
    
    func main() {
        // Creates an application without any middleware by default.
        app := iris.New()
    
        // Recover middleware recovers from any panics and writes a 500 if there was one.
        app.Use(recover.New())
    
        requestLogger := logger.New(logger.Config{
            // Status displays status code
            Status: true,
            // IP displays request's remote address
            IP: true,
            // Method displays the http method
            Method: true,
            // Path displays the request path
            Path: true,
            // Query appends the url query to the Path.
            Query: true,
    
            // if !empty then its contents derives from `ctx.Values().Get("logger_message")
            // will be added to the logs.
            MessageContextKeys: []string{"logger_message"},
    
            // if !empty then its contents derives from `ctx.GetHeader("User-Agent")
            MessageHeaderKeys: []string{"User-Agent"},
        })
        app.Use(requestLogger)
    
        // Per route middleware, you can add as many as you desire.
        app.Get("/benchmark", MyBenchLogger(), benchEndpoint)
    
        // Authorization party /user.
        // authorized := app.Party("/user", AuthRequired())
        // exactly the same as:
        authorized := app.Party("/user")
        // per party middleware! in this case we use the custom created
        // AuthRequired() middleware just in the "authorized" group/party.
        authorized.Use(AuthRequired())
        {
            authorized.Post("/login", loginEndpoint)
            authorized.Post("/submit", submitEndpoint)
            authorized.Post("/read", readEndpoint)
    
            // nested group: /user/testing
            testing := authorized.Party("/testing")
            testing.Get("/analytics", analyticsEndpoint)
        }
    
        // Listen and serve on http://0.0.0.0:8080
        app.Run(iris.Addr(":8080"))
    }

    How to write log file

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    
    package main
    
    import (
    	"os"
    	"time"
    
    	"github.com/kataras/iris"
    )
    
    // Get a filename based on the date, just for the sugar.
    func todayFilename() string {
        today := time.Now().Format("Jan 02 2006")
        return today + ".txt"
    }
    
    func newLogFile() *os.File {
        filename := todayFilename()
        // Open the file, this will append to the today's file if server restarted.
        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()
        // Attach the file as logger, remember, iris' app logger is just an io.Writer.
        // Use the following code if you need to write the logs to file and console at the same time.
        // app.Logger().SetOutput(io.MultiWriter(f, os.Stdout))
        app.Logger().SetOutput(f)
    
        app.Get("/ping", func(ctx iris.Context) {
            // for the sake of simplicity, in order see the logs at the ./_today_.txt
            ctx.Application().Logger().Infof("Request path: %s", ctx.Path())
            ctx.WriteString("pong")
        })
    
        // Navigate to http://localhost:8080/ping
        // and open the ./logs{TODAY}.txt file.
        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".

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    
    package main
    
    import (
        "fmt"
    
        "github.com/kataras/iris"
        "gopkg.in/go-playground/validator.v9"
    )
    
    // User contains user information.
    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"`
    }
    
    // Address houses a users address information.
    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"`
    }
    
    // Use a single instance of Validate, it caches struct info.
    var validate *validator.Validate
    
    func main() {
        validate = validator.New()
    
        // Register validation for 'User'
        // NOTE: only have to register a non-pointer type for 'User', validator
        // internally dereferences during it's type checks.
        validate.RegisterStructValidation(UserStructLevelValidation, User{})
    
        app := iris.New()
        app.Post("/user", func(ctx iris.Context) {
            var user User
            if err := ctx.ReadJSON(&user); err != nil {
                // Handle error.
            }
    
            // Returns InvalidValidationError for bad validation input,
            // nil or ValidationErrors ( []FieldError )
            err := validate.Struct(user)
            if err != nil {
    
                // This check is only needed when your code could produce
                // an invalid value for validation such as interface with nil
                // value most including myself do not usually have code like this.
                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
            }
    
            // save user to database.
        })
    
        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", "")
        }
    }
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    {
        "fname": "",
        "lname": "",
        "age": 45,
        "email": "mail@example.com",
        "favColor": "#000",
        "addresses": [{
            "street": "Eavesdown Docks",
            "planet": "Persphone",
            "phone": "none",
            "city": "Unknown"
        }]
    }

    Cookies

    Are you looking for http sessions instead?

    Let’s write a simple application which will make use of the HTTP Cookies.

    $ cat _examples/cookies/basic/main.go
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    
    package main
    
    import "github.com/kataras/iris"
    
    func newApp() *iris.Application {
        app := iris.New()
    
        // Set A Cookie.
        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)
        })
    
        // Retrieve A Cookie.
        app.Get("/cookies/{name}", func(ctx iris.Context) {
            name := ctx.Params().Get("name")
    
            value := ctx.GetCookie(name)
    
            ctx.WriteString(value)
        })
    
        // Delete A Cookie.
        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()
    
        // GET:    http://localhost:8080/cookies/my_name/my_value
        // GET:    http://localhost:8080/cookies/my_name
        // DELETE: http://localhost:8080/cookies/my_name
        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. The iris/httptest subpackage provides helpers for Iris + httpexpect.

    if you prefer the Go’s standard net/http/httptest package, you can still use it. Iris as much every http web framework is compatible with any external tool for testing, at the end it’s HTTP.

    Basic Authentication

    In our first example we will use the iris/httptest to test Basic Authentication.

    1. The main.go source file looks like that:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    
    package main
    
    import (
        "github.com/kataras/iris"
        "github.com/kataras/iris/middleware/basicauth"
    )
    
    func newApp() *iris.Application {
        app := iris.New()
    
        authConfig := basicauth.Config{
            Users: map[string]string{"myusername": "mypassword"},
        }
    
        authentication := basicauth.New(authConfig)
    
        app.Get("/", func(ctx iris.Context) { ctx.Redirect("/admin") })
    
        needAuth := app.Party("/admin", authentication)
        {
            //http://localhost:8080/admin
            needAuth.Get("/", h)
            // http://localhost:8080/admin/profile
            needAuth.Get("/profile", h)
    
            // http://localhost:8080/admin/settings
            needAuth.Get("/settings", h)
        }
    
        return app
    }
    
    func h(ctx iris.Context) {
        username, password, _ := ctx.Request().BasicAuth()
        // third parameter  ^ will be always true because the middleware
        // makes sure for that, otherwise this handler will not be executed.
    
        ctx.Writef("%s %s:%s", ctx.Path(), username, password)
    }
    
    func main() {
        app := newApp()
        app.Run(iris.Addr(":8080"))
    }

    2. Now, create a main_test.go file and copy-paste the following.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
    package main
    
    import (
        "testing"
    
        "github.com/kataras/iris/httptest"
    )
    
    func TestNewApp(t *testing.T) {
        app := newApp()
        e := httptest.New(t, app)
    
        // redirects to /admin without basic auth
        e.GET("/").Expect().Status(httptest.StatusUnauthorized)
        // without basic auth
        e.GET("/admin").Expect().Status(httptest.StatusUnauthorized)
    
        // with valid basic auth
        e.GET("/admin").WithBasicAuth("myusername", "mypassword").Expect().
            Status(httptest.StatusOK).Body().Equal("/admin myusername:mypassword")
        e.GET("/admin/profile").WithBasicAuth("myusername", "mypassword").Expect().
            Status(httptest.StatusOK).Body().Equal("/admin/profile myusername:mypassword")
        e.GET("/admin/settings").WithBasicAuth("myusername", "mypassword").Expect().
            Status(httptest.StatusOK).Body().Equal("/admin/settings myusername:mypassword")
    
        // with invalid basic auth
        e.GET("/admin/settings").WithBasicAuth("invalidusername", "invalidpassword").
            Expect().Status(httptest.StatusUnauthorized)
    
    }

    3. Open your command line and execute:

    $ go test -v

    Other example: cookies

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    
    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"
    
        // Test Set A Cookie.
        t1 := e.GET(fmt.Sprintf("/cookies/%s/%s", cookieName, cookieValue)).
            Expect().Status(httptest.StatusOK)
        // Validate cookie's existence, it should be available now.
        t1.Cookie(cookieName).Value().Equal(cookieValue)
        t1.Body().Contains(cookieValue)
    
        path := fmt.Sprintf("/cookies/%s", cookieName)
    
        // Test Retrieve A Cookie.
        t2 := e.GET(path).Expect().Status(httptest.StatusOK)
        t2.Body().Equal(cookieValue)
    
        // Test Remove A Cookie.
        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()
    }
    $ go test -v -run=TestCookiesBasic$

    Iris web framework itself uses this package to test itself. In the _examples repository directory you will find some useful tests as well. For more information please take a look and read the httpexpect’s documentation.