1
0
mirror of https://github.com/kataras/iris.git synced 2025-12-24 05:17:03 +00:00

Publish the new version ✈️ | Look description please!

# FAQ

### Looking for free support?

	http://support.iris-go.com
    https://kataras.rocket.chat/channel/iris

### Looking for previous versions?

    https://github.com/kataras/iris#version

### Should I upgrade my Iris?

Developers are not forced to upgrade if they don't really need it. Upgrade whenever you feel ready.
> Iris uses the [vendor directory](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo) feature, so you get truly reproducible builds, as this method guards against upstream renames and deletes.

**How to upgrade**: Open your command-line and execute this command: `go get -u github.com/kataras/iris`.
For further installation support, please click [here](http://support.iris-go.com/d/16-how-to-install-iris-web-framework).

### About our new home page
    http://iris-go.com

Thanks to [Santosh Anand](https://github.com/santoshanand) the http://iris-go.com has been upgraded and it's really awesome!

[Santosh](https://github.com/santoshanand) is a freelancer, he has a great knowledge of nodejs and express js, Android, iOS, React Native, Vue.js etc, if you need a developer to find or create a solution for your problem or task, please contact with him.

The amount of the next two or three donations you'll send they will be immediately transferred to his own account balance, so be generous please!

Read more at https://github.com/kataras/iris/blob/master/HISTORY.md


Former-commit-id: eec2d71bbe011d6b48d2526eb25919e36e5ad94e
This commit is contained in:
kataras
2017-06-03 23:22:52 +03:00
parent 03bcadadec
commit 5e4b63acb2
330 changed files with 35786 additions and 17316 deletions

View File

@@ -1,35 +0,0 @@
package main
import (
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
"gopkg.in/kataras/iris.v6/adaptors/typescript" // optinally
"gopkg.in/kataras/iris.v6/adaptors/typescript/editor"
)
func main() {
app := iris.New()
app.Adapt(iris.DevLogger())
app.Adapt(httprouter.New()) // adapt a router, order doesn't matters
// optionally but good to have, I didn't put inside editor or the editor in the typescript compiler adaptors
// because you may use tools like gulp and you may use the editor without the typescript compiler adaptor.
// but if you need auto-compilation on .ts, we have a solution:
ts := typescript.New()
ts.Config.Dir = "./www/scripts/"
app.Adapt(ts) // adapt the typescript compiler adaptor
editorConfig := editor.Config{
Hostname: "127.0.0.1",
Port: 4444,
WorkingDir: "./www/scripts/", // "/path/to/the/client/side/directory/",
Username: "myusername",
Password: "mypassword",
}
e := editor.New(editorConfig)
app.Adapt(e) // adapt the editor
app.StaticWeb("/", "./www") // serve the index.html
app.Listen(":8080")
}

View File

@@ -1,8 +0,0 @@
<html>
<head>
<title>Load my script (lawl)</title>
</head>
<body>
<script src="scripts/app.js"></script>
</body>
</html>

View File

@@ -1,16 +0,0 @@
class User{
private name: string;
constructor(fullname:string) {
this.name = fullname;
}
Hi(msg: string): string {
return msg + " " + this.name;
}
}
var user = new User("kataras");
var hi = user.Hi("Hello");
window.alert(hi);

View File

@@ -1,22 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": false,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": false,
"target": "ES5",
"noEmit": false,
"watch":true,
"noEmitOnError": true,
"experimentalDecorators": false,
"outDir": "./",
"charset": "UTF-8",
"noLib": false,
"diagnostics": true,
"declaration": false
},
"files": [
"./app.ts"
]
}

View File

@@ -1,41 +0,0 @@
package main
import (
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
"gopkg.in/kataras/iris.v6/adaptors/sessions"
)
func newApp() *iris.Framework {
app := iris.New()
app.Adapt(httprouter.New())
app.Adapt(sessions.New(sessions.Config{Cookie: "mysessionid"}))
app.Get("/hello", func(ctx *iris.Context) {
sess := ctx.Session()
if !sess.HasFlash() /* or sess.GetFlash("name") == "", same thing here */ {
ctx.HTML(iris.StatusUnauthorized, "<h1> Unauthorized Page! </h1>")
return
}
ctx.JSON(iris.StatusOK, iris.Map{
"Message": "Hello",
"From": sess.GetFlash("name"),
})
})
app.Post("/login", func(ctx *iris.Context) {
sess := ctx.Session()
if !sess.HasFlash() {
sess.SetFlash("name", ctx.FormValue("name"))
}
// let's no redirect, just set the flash message, nothing more.
})
return app
}
func main() {
app := newApp()
app.Listen(":8080")
}

View File

@@ -1,32 +0,0 @@
package main
import (
"testing"
"gopkg.in/kataras/iris.v6/httptest"
)
// $ cd _example
// $ go test -v
func TestNewApp(t *testing.T) {
app := newApp()
e := httptest.New(app, t)
// test nauthorized
e.GET("/hello").Expect().Status(401).Body().Equal("<h1> Unauthorized Page! </h1>")
// test our login flash message
name := "myname"
e.POST("/login").WithFormField("name", name).Expect().Status(200)
// test the /hello again with the flash (a message which deletes itself after it has been shown to the user)
// setted on /login previously.
expectedResponse := map[string]interface{}{
"Message": "Hello",
"From": name,
}
e.GET("/hello").Expect().Status(200).JSON().Equal(expectedResponse)
// test /hello nauthorized again, it should be return 401 now (flash should be removed)
e.GET("/hello").Expect().Status(401).Body().Equal("<h1> Unauthorized Page! </h1>")
}
// for advanced test examples navigate there:
// https://github.com/gavv/httpexpect/blob/master/_examples/iris_test.go

View File

@@ -3,30 +3,27 @@ package main
import (
"sync/atomic"
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
"gopkg.in/kataras/iris.v6/adaptors/view"
"gopkg.in/kataras/iris.v6/adaptors/websocket"
"github.com/kataras/iris"
"github.com/kataras/iris/context"
"github.com/kataras/iris/view"
"github.com/kataras/iris/websocket"
)
var (
app *iris.Framework
app *iris.Application
ws websocket.Server
)
func init() {
// init the server instance
app = iris.New()
// adapt a logger in dev mode
app.Adapt(iris.DevLogger())
// adapt router
app.Adapt(httprouter.New())
// adapt templaes
app.Adapt(view.HTML("./templates", ".html").Reload(true))
// adapt websocket
// load templaes
app.AttachView(view.HTML("./templates", ".html").Reload(true))
// attach websocket server
ws = websocket.New(websocket.Config{Endpoint: "/my_endpoint"})
ws.OnConnection(HandleWebsocketConnection)
app.Adapt(ws)
ws.Attach(app)
}
type page struct {
@@ -36,21 +33,23 @@ type page struct {
func main() {
app.StaticWeb("/js", "./static/assets/js")
h := func(ctx *iris.Context) {
ctx.Render("index.html", page{PageID: "index page"})
h := func(ctx context.Context) {
ctx.ViewData("", page{PageID: "index page"})
ctx.View("index.html")
}
h2 := func(ctx *iris.Context) {
ctx.Render("other.html", page{PageID: "other page"})
h2 := func(ctx context.Context) {
ctx.ViewData("", page{PageID: "other page"})
ctx.View("other.html")
}
// Open some browser tabs/or windows
// and navigate to
// http://localhost:8080/ and http://localhost:8080/other
// http://localhost:8080/ and http://localhost:8080/other multiple times.
// Each page has its own online-visitors counter.
app.Get("/", h)
app.Get("/other", h2)
app.Listen(":8080")
app.Run(iris.Addr(":8080"))
}
type pageView struct {

View File

@@ -1,28 +0,0 @@
# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host
# localhost name resolution is handled within DNS itself.
127.0.0.1 localhost
::1 localhost
#-IRIS-For development machine, you have to configure your dns also for online, search google how to do it if you don't know
127.0.0.1 domain.local
127.0.0.1 system.domain.local
127.0.0.1 dashboard.domain.local
#-END IRIS-

View File

@@ -1,39 +0,0 @@
package main
import (
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
)
func main() {
app := iris.New()
app.Adapt(iris.DevLogger())
// subdomains works with all available routers, like other features too.
app.Adapt(httprouter.New())
/*
* Setup static files
*/
app.StaticWeb("/assets", "./public/assets")
app.StaticWeb("/upload_resources", "./public/upload_resources")
dashboard := app.Party("dashboard.")
{
dashboard.Get("/", func(ctx *iris.Context) {
ctx.Writef("HEY FROM dashboard")
})
}
system := app.Party("system.")
{
system.Get("/", func(ctx *iris.Context) {
ctx.Writef("HEY FROM system")
})
}
app.Get("/", func(ctx *iris.Context) {
ctx.Writef("HEY FROM frontend /")
})
/* test this on firefox, because the domain is not real (because of .local), on firefox this will fail, but you can test it with other domain */
app.Listen("domain.local:80") // for beginners: look ../hosts file
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

View File

@@ -1,27 +0,0 @@
# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host
# localhost name resolution is handled within DNS itself.
127.0.0.1 localhost
::1 localhost
#-IRIS-For development machine, you have to configure your dns also for online, search google how to do it if you don't know
127.0.0.1 mydomain.com
127.0.0.1 admin.mydomain.com
#-END IRIS-

View File

@@ -1,43 +0,0 @@
// Package main register static subdomains, simple as parties, check ./hosts if you use windows
package main
import (
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
)
func main() {
app := iris.New()
app.Adapt(iris.DevLogger())
// subdomains works with all available routers, like other features too.
app.Adapt(httprouter.New())
// no order, you can register subdomains at the end also.
admin := app.Party("admin.")
{
// admin.mydomain.com
admin.Get("/", func(c *iris.Context) {
c.Writef("INDEX FROM admin.mydomain.com")
})
// admin.mydomain.com/hey
admin.Get("/hey", func(c *iris.Context) {
c.Writef("HEY FROM admin.mydomain.com/hey")
})
// admin.mydomain.com/hey2
admin.Get("/hey2", func(c *iris.Context) {
c.Writef("HEY SECOND FROM admin.mydomain.com/hey")
})
}
// mydomain.com/
app.Get("/", func(c *iris.Context) {
c.Writef("INDEX FROM no-subdomain hey")
})
// mydomain.com/hey
app.Get("/hey", func(c *iris.Context) {
c.Writef("HEY FROM no-subdomain hey")
})
app.Listen("mydomain.com:80") // for beginners: look ../hosts file
}

View File

@@ -1,30 +0,0 @@
# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host
# localhost name resolution is handled within DNS itself.
127.0.0.1 localhost
::1 localhost
#-IRIS-For development machine, you have to configure your dns also for online, search google how to do it if you don't know
127.0.0.1 mydomain.com
127.0.0.1 username1.mydomain.com
127.0.0.1 username2.mydomain.com
127.0.0.1 username3.mydomain.com
127.0.0.1 username4.mydomain.com
127.0.0.1 username5.mydomain.com
#-END IRIS-

View File

@@ -1,71 +0,0 @@
// Package main an example on how to catch dynamic subdomains - wildcard.
// On the first example (subdomains_1) we saw how to create routes for static subdomains, subdomains you know that you will have.
// Here we will see an example how to catch unknown subdomains, dynamic subdomains, like username.mydomain.com:8080.
package main
import (
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
)
// register a dynamic-wildcard subdomain to your server machine(dns/...) first, check ./hosts if you use windows.
// run this file and try to redirect: http://username1.mydomain.com:8080/ , http://username2.mydomain.com:8080/ , http://username1.mydomain.com/something, http://username1.mydomain.com/something/sadsadsa
func main() {
app := iris.New()
app.Adapt(iris.DevLogger())
// subdomains works with all available routers, like other features too.
app.Adapt(httprouter.New())
/* Keep note that you can use both type of subdomains (named and wildcard(*.) )
admin.mydomain.com, and for other the Party(*.) but this is not this example's purpose
admin := app.Party("admin.")
{
// admin.mydomain.com
admin.Get("/", func(ctx *iris.Context) {
ctx.Writef("INDEX FROM admin.mydomain.com")
})
// admin.mydomain.com/hey
admin.Get("/hey", func(ctx *iris.Context) {
ctx.Writef("HEY FROM admin.mydomain.com/hey")
})
// admin.mydomain.com/hey2
admin.Get("/hey2", func(ctx *iris.Context) {
ctx.Writef("HEY SECOND FROM admin.mydomain.com/hey")
})
}*/
// no order, you can register subdomains at the end also.
dynamicSubdomains := app.Party("*.")
{
dynamicSubdomains.Get("/", dynamicSubdomainHandler)
dynamicSubdomains.Get("/something", dynamicSubdomainHandler)
dynamicSubdomains.Get("/something/:param1", dynamicSubdomainHandlerWithParam)
}
app.Get("/", func(ctx *iris.Context) {
ctx.Writef("Hello from mydomain.com path: %s", ctx.Path())
})
app.Get("/hello", func(ctx *iris.Context) {
ctx.Writef("Hello from mydomain.com path: %s", ctx.Path())
})
app.Listen("mydomain.com:8080") // for beginners: look ../hosts file
}
func dynamicSubdomainHandler(ctx *iris.Context) {
username := ctx.Subdomain()
ctx.Writef("Hello from dynamic subdomain path: %s, here you can handle the route for dynamic subdomains, handle the user: %s", ctx.Path(), username)
// if http://username4.mydomain.com:8080/ prints:
// Hello from dynamic subdomain path: /, here you can handle the route for dynamic subdomains, handle the user: username4
}
func dynamicSubdomainHandlerWithParam(ctx *iris.Context) {
username := ctx.Subdomain()
ctx.Writef("Hello from dynamic subdomain path: %s, here you can handle the route for dynamic subdomains, handle the user: %s", ctx.Path(), username)
ctx.Writef("THE PARAM1 is: %s", ctx.Param("param1"))
}

View File

@@ -1,56 +0,0 @@
package main
import (
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
)
func main() {
app := iris.New()
app.Adapt(iris.DevLogger())
// subdomains works with all available routers, like other features too.
app.Adapt(httprouter.New())
app.Get("/", func(ctx *iris.Context) {
ctx.BeginTransaction(func(t *iris.Transaction) {
// OPTIONAl STEP: , if true then the next transictions will not be executed if this transiction fails
// t.SetScope(iris.RequestTransactionScope)
// OPTIONAL STEP:
// create a new custom type of error here to keep track of the status code and reason message
err := iris.NewTransactionErrResult()
// we should use t.Context if we want to rollback on any errors lives inside this function clojure.
t.Context.Text(iris.StatusOK, "Blablabla this should not be sent to the client because we will fill the err with a message and status")
// virtualize a fake error here, for the shake of the example
fail := true
if fail {
err.StatusCode = iris.StatusInternalServerError
// NOTE: if empty reason then the default or the custom http error will be fired (like ctx.EmitError)
err.Reason = "Error: Virtual failure!!"
}
// OPTIONAl STEP:
// but useful if we want to post back an error message to the client if the transaction failed.
// if the reason is empty then the transaction completed succesfuly,
// otherwise we rollback the whole response writer's body,
// headers and cookies, status code and everything lives inside this transaction
t.Complete(err)
})
ctx.BeginTransaction(func(t *iris.Transaction) {
t.Context.HTML(iris.StatusOK,
"<h1>This will sent at all cases because it lives on different transaction and it doesn't fails</h1>")
// * if we don't have any 'throw error' logic then no need of scope.Complete()
})
// OPTIONAL, depends on the usage:
// at any case, what ever happens inside the context's transactions send this to the client
ctx.HTML(iris.StatusOK, "<h1>Let's add a second html message to the response, "+
"if the transaction was failed and it was request scoped then this message would "+
"not been shown. But it has a transient scope(default) so, it is visible as expected!</h1>")
})
app.Listen(":8080")
}

View File

@@ -1,36 +0,0 @@
package main
import (
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
"gopkg.in/kataras/iris.v6/adaptors/typescript"
)
// NOTE: Some machines don't allow to install typescript automatically, so if you don't have typescript installed
// and the typescript adaptor doesn't works for you then follow the below steps:
// 1. close the iris server
// 2. open your terminal and execute: npm install -g typescript
// 3. start your iris server, it should be work, as expected, now.
func main() {
app := iris.New()
app.Adapt(iris.DevLogger())
app.Adapt(httprouter.New()) // adapt a router, order doesn't matters but before Listen.
ts := typescript.New()
ts.Config.Dir = "./www/scripts"
app.Adapt(ts) // adapt the typescript compiler adaptor
app.StaticWeb("/", "./www") // serve the index.html
app.Listen(":8080")
}
// open http://localhost:8080
// go to ./www/scripts/app.ts
// make a change
// reload the http://localhost:8080 and you should see the changes
//
// what it does?
// - compiles the typescript files using default compiler options if not tsconfig found
// - watches for changes on typescript files, if a change then it recompiles the .ts to .js
//
// same as you used to do with gulp-like tools, but here at Iris I do my bests to help GO developers.

View File

@@ -1,8 +0,0 @@
<html>
<head>
<title>Load my script (lawl)</title>
</head>
<body>
<script src="scripts/app.js"></script>
</body>
</html>

View File

@@ -1,16 +0,0 @@
class User{
private name: string;
constructor(fullname:string) {
this.name = fullname;
}
Hi(msg: string): string {
return msg + " "+ this.name;
}
}
var user = new User("kataras");
var hi = user.Hi("Hello");
window.alert(hi);

View File

@@ -13,21 +13,11 @@ import (
"time"
"github.com/boltdb/bolt"
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
"gopkg.in/kataras/iris.v6/adaptors/view"
)
"github.com/kataras/iris"
"github.com/kataras/iris/context"
// a custom Iris event policy, which will run when server interruped (i.e control+C)
// receives a func() error, most of packages are compatible with that on their Close/Shutdown/Cancel funcs.
func releaser(r func() error) iris.EventPolicy {
return iris.EventPolicy{
Interrupted: func(app *iris.Framework) {
if err := r(); err != nil {
app.Log(iris.ProdMode, "error while releasing resources: "+err.Error())
}
}}
}
"github.com/kataras/iris/view"
)
func main() {
app := iris.New()
@@ -36,83 +26,77 @@ func main() {
db := NewDB("shortener.db")
factory := NewFactory(DefaultGenerator, db)
app.Adapt(
// print all kind of errors and logs at os.Stdout
iris.DevLogger(),
// use the httprouter, you can use adpaotrs/gorillamux if you want
httprouter.New(),
// serve the "./templates" directory's "*.html" files with the HTML std view engine.
view.HTML("./templates", ".html").Reload(true),
// `db.Close` is a `func() error` so it can be a `releaser` too.
// Wrap the db.Close with the releaser in order to be released when app exits or control+C
// You probably never saw that before, clever pattern which I am able to use only with Iris :)
releaser(db.Close),
)
// serve the "./templates" directory's "*.html" files with the HTML std view engine.
tmpl := view.HTML("./templates", ".html").Reload(true)
// template funcs
//
// look ./templates/index.html#L16
app.Adapt(iris.TemplateFuncsPolicy{"isPositive": func(n int) bool {
tmpl.AddFunc("isPositive", func(n int) bool {
if n > 0 {
return true
}
return false
}})
})
app.AttachView(tmpl)
// Serve static files (css)
app.StaticWeb("/static", "./resources")
app.Get("/", func(ctx *iris.Context) {
ctx.MustRender("index.html", iris.Map{"url_count": db.Len()})
app.Get("/", func(ctx context.Context) {
ctx.ViewData("url_count", db.Len())
ctx.View("index.html")
})
// find and execute a short url by its key
// used on http://localhost:8080/u/dsaoj41u321dsa
execShortURL := func(ctx *iris.Context, key string) {
execShortURL := func(ctx context.Context, key string) {
if key == "" {
ctx.EmitError(iris.StatusBadRequest)
ctx.StatusCode(iris.StatusBadRequest)
return
}
value := db.Get(key)
if value == "" {
ctx.SetStatusCode(iris.StatusNotFound)
ctx.StatusCode(iris.StatusNotFound)
ctx.Writef("Short URL for key: '%s' not found", key)
return
}
ctx.Redirect(value, iris.StatusTemporaryRedirect)
}
app.Get("/u/:shortkey", func(ctx *iris.Context) {
execShortURL(ctx, ctx.Param("shortkey"))
app.Get("/u/:shortkey", func(ctx context.Context) {
execShortURL(ctx, ctx.Params().Get("shortkey"))
})
app.Post("/shorten", func(ctx *iris.Context) {
data := make(map[string]interface{}, 0)
app.Post("/shorten", func(ctx context.Context) {
formValue := ctx.FormValue("url")
if formValue == "" {
data["form_result"] = "You need to a enter a URL."
ctx.ViewData("form_result", "You need to a enter a URL")
} else {
key, err := factory.Gen(formValue)
if err != nil {
data["form_result"] = "Invalid URL."
ctx.ViewData("form_result", "Invalid URL")
} else {
if err = db.Set(key, formValue); err != nil {
data["form_result"] = "Internal error while saving the url"
app.Log(iris.DevMode, "while saving url: "+err.Error())
ctx.ViewData("form_result", "Internal error while saving the URL")
app.Log("while saving URL: " + err.Error())
} else {
ctx.SetStatusCode(iris.StatusOK)
shortenURL := "http://" + app.Config.VHost + "/u/" + key
data["form_result"] = template.HTML("<pre><a target='_new' href='" + shortenURL + "'>" + shortenURL + " </a></pre>")
ctx.StatusCode(iris.StatusOK)
shortenURL := "http://" + app.ConfigurationReadOnly().GetVHost() + "/u/" + key
ctx.ViewData("form_result",
template.HTML("<pre><a target='_new' href='"+shortenURL+"'>"+shortenURL+" </a></pre>"))
}
}
}
data["url_count"] = db.Len()
ctx.Render("index.html", data)
ctx.ViewData("url_count", db.Len())
ctx.View("index.html")
})
app.Listen("localhost:8080")
app.Run(iris.Addr(":8080"))
db.Close()
}
// +------------------------------------------------------------+