mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
replace ioutil with io package and other minor improvements
This commit is contained in:
parent
20d2855a66
commit
ef2643b046
|
@ -28,6 +28,7 @@ The codebase for Dependency Injection, Internationalization and localization and
|
||||||
|
|
||||||
## Fixes and Improvements
|
## Fixes and Improvements
|
||||||
|
|
||||||
|
- Make the `Context.JSON` method customizable by modifying the `context.WriteJSON` package-level function.
|
||||||
- Add new `iris.NewGuide` which helps you build a simple and nice JSON API with services as dependencies and better design pattern.
|
- Add new `iris.NewGuide` which helps you build a simple and nice JSON API with services as dependencies and better design pattern.
|
||||||
- Make `Context.Domain()` customizable by letting developers to modify the `Context.GetDomain` package-level function.
|
- Make `Context.Domain()` customizable by letting developers to modify the `Context.GetDomain` package-level function.
|
||||||
- Remove Request Context-based Transaction feature as its usage can be replaced with just the Iris Context (as of go1.7+) and better [project](_examples/project) structure.
|
- Remove Request Context-based Transaction feature as its usage can be replaced with just the Iris Context (as of go1.7+) and better [project](_examples/project) structure.
|
||||||
|
|
5
LICENSE
5
LICENSE
|
@ -1,4 +1,7 @@
|
||||||
Copyright (c) 2017-2022 The Iris Authors. All rights reserved.
|
Copyright (c) 2017-2022, The Iris Authors. All rights reserved.
|
||||||
|
|
||||||
|
The Iris Authors:
|
||||||
|
* Gerasimos (Makis) Maropoulos
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are
|
modification, are permitted provided that the following conditions are
|
||||||
|
|
45
README.md
45
README.md
|
@ -19,7 +19,8 @@
|
||||||
|
|
||||||
Iris is a fast, simple yet fully featured and very efficient web framework for Go.
|
Iris is a fast, simple yet fully featured and very efficient web framework for Go.
|
||||||
|
|
||||||
It provides a [beautifully](iris_guide.go#L31-L44) expressive and easy to use foundation for your next website or API.
|
It provides a beautifully expressive and easy to use foundation for your next website or API.
|
||||||
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
@ -27,18 +28,18 @@ package main
|
||||||
import "github.com/kataras/iris/v12"
|
import "github.com/kataras/iris/v12"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
app.Use(iris.Compression)
|
app.Use(iris.Compression)
|
||||||
|
|
||||||
app.Get("/", func(ctx iris.Context) {
|
app.Get("/", func(ctx iris.Context) {
|
||||||
ctx.HTML("Hello <strong>%s</strong>!", "World")
|
ctx.HTML("Hello <strong>%s</strong>!", "World")
|
||||||
})
|
})
|
||||||
|
|
||||||
app.Listen(":8080")
|
app.Listen(":8080")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<details><summary>More with simple Handler</summary>
|
<!-- <details><summary>More with simple Handler</summary>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
@ -178,6 +179,34 @@ func main() {
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
As one [Go developer](https://twitter.com/dkuye/status/1532087942696554497) once said, **Iris got you covered all-round and standing strong over the years**.
|
||||||
|
|
||||||
|
Some of the features Iris offers:
|
||||||
|
|
||||||
|
* HTTP/2 (Push, even Embedded data)
|
||||||
|
* Middleware (Accesslog, Basicauth, CORS, gRPC, Anti-Bot hCaptcha, JWT, MethodOverride, ModRevision, Monitor, PPROF, Ratelimit, Anti-Bot reCaptcha, Recovery, RequestID, Rewrite)
|
||||||
|
* API Versioning
|
||||||
|
* Model-View-Controller
|
||||||
|
* Websockets
|
||||||
|
* gRPC
|
||||||
|
* Auto-HTTPS
|
||||||
|
* Builtin support for ngrok to put your app on the internet, the fastest way
|
||||||
|
* Unique Router with dynamic path as parameter with standard types like :uuid, :string, :int... and the ability to create your own
|
||||||
|
* Compression
|
||||||
|
* View Engines (HTML, Django, Amber, Handlebars, Pug/Jade and more)
|
||||||
|
* Create your own File Server and host your own WebDAV server
|
||||||
|
* Cache
|
||||||
|
* Localization (i18n, sitemap)
|
||||||
|
* Sessions
|
||||||
|
* Rich Responses (HTML, Text, Markdown, XML, YAML, Binary, JSON, JSONP, Protocol Buffers, MessagePack, Content Negotiation, Streaming, Server-Sent Events and more)
|
||||||
|
* Response Compression (gzip, deflate, brotli, snappy, s2)
|
||||||
|
* Rich Requests (Bind URL Query, Headers, Form, Text, XML, YAML, Binary, JSON, Validation, Protocol Buffers, MessagePack and more)
|
||||||
|
* Dependency Injection (MVC, Handlers, API Routers)
|
||||||
|
* Testing Suite
|
||||||
|
* And the most important... you get fast answers and support from the 1st day until now - that's six full years!
|
||||||
|
|
||||||
Learn what [others saying about Iris](https://www.iris-go.com/#review) and **[star](https://github.com/kataras/iris/stargazers)** this open-source project to support its potentials.
|
Learn what [others saying about Iris](https://www.iris-go.com/#review) and **[star](https://github.com/kataras/iris/stargazers)** this open-source project to support its potentials.
|
||||||
|
|
||||||
[![](https://iris-go.com/images/reviews.gif)](https://iris-go.com/testimonials/)
|
[![](https://iris-go.com/images/reviews.gif)](https://iris-go.com/testimonials/)
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -105,5 +104,5 @@ func BindResponse(resp *http.Response, dest interface{}) error {
|
||||||
func RawResponse(resp *http.Response) ([]byte, error) {
|
func RawResponse(resp *http.Response) ([]byte, error) {
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
return ioutil.ReadAll(resp.Body)
|
return io.ReadAll(resp.Body)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/kataras/iris/v12/context"
|
"github.com/kataras/iris/v12/context"
|
||||||
|
@ -51,7 +51,7 @@ func getExample() {
|
||||||
}
|
}
|
||||||
defer cr.Close()
|
defer cr.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(cr)
|
body, err := io.ReadAll(cr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ func postExample() {
|
||||||
}
|
}
|
||||||
defer cr.Close()
|
defer cr.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(cr)
|
body, err := io.ReadAll(cr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ func getExample() {
|
||||||
}
|
}
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(r)
|
body, err := io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ func postExample() {
|
||||||
}
|
}
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(r)
|
body, err := io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
const addr = "127.0.0.1:8080"
|
const addr = "127.0.0.1:8080"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
$ go build -mod=mod -ldflags -H=windowsgui -o myapp.exe
|
$ go build -mod=mod -ldflags -H=windowsgui -o myapp.exe
|
||||||
$ ./myapp.exe # run the app
|
$ ./myapp.exe # run the app
|
||||||
*/
|
*/
|
||||||
func main() {
|
func main() {
|
||||||
go runServer()
|
go runServer()
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
const addr = "127.0.0.1:8080"
|
const addr = "127.0.0.1:8080"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
|
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
|
||||||
$ ./myapp.exe # run
|
$ ./myapp.exe # run
|
||||||
*/
|
*/
|
||||||
func main() {
|
func main() {
|
||||||
go runServer()
|
go runServer()
|
||||||
|
|
|
@ -8,21 +8,21 @@ import (
|
||||||
const addr = "127.0.0.1:8080"
|
const addr = "127.0.0.1:8080"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
# Windows requires special linker flags for GUI apps.
|
# Windows requires special linker flags for GUI apps.
|
||||||
# It's also recommended to use TDM-GCC-64 compiler for CGo.
|
# It's also recommended to use TDM-GCC-64 compiler for CGo.
|
||||||
# http://tdm-gcc.tdragon.net/download
|
# http://tdm-gcc.tdragon.net/download
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
|
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
|
||||||
$ ./myapp.exe # run
|
$ ./myapp.exe # run
|
||||||
#
|
#
|
||||||
# MacOS uses app bundles for GUI apps
|
# MacOS uses app bundles for GUI apps
|
||||||
$ mkdir -p example.app/Contents/MacOS
|
$ mkdir -p example.app/Contents/MacOS
|
||||||
$ go build -o example.app/Contents/MacOS/example
|
$ go build -o example.app/Contents/MacOS/example
|
||||||
$ open example.app # Or click on the app in Finder
|
$ open example.app # Or click on the app in Finder
|
||||||
#
|
#
|
||||||
# Note: if you see "use option -std=c99 or -std=gnu99 to compile your code"
|
# Note: if you see "use option -std=c99 or -std=gnu99 to compile your code"
|
||||||
# please refer to: https://github.com/webview/webview/issues/188
|
# please refer to: https://github.com/webview/webview/issues/188
|
||||||
*/
|
*/
|
||||||
func main() {
|
func main() {
|
||||||
go runServer()
|
go runServer()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -47,7 +47,7 @@ func (r resource) loadFromBase(dir string, strip string) string {
|
||||||
|
|
||||||
fullpath := filepath.Join(dir, filename)
|
fullpath := filepath.Join(dir, filename)
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(fullpath)
|
b, err := os.ReadFile(fullpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fullpath + " failed with error: " + err.Error())
|
panic(fullpath + " failed with error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||||
|
|
||||||
//Package main generated by go-bindata.// sources:
|
// Package main generated by go-bindata.// sources:
|
||||||
// assets/css/main.css
|
// assets/css/main.css
|
||||||
// assets/favicon.ico
|
// assets/favicon.ico
|
||||||
// assets/js/main.js
|
// assets/js/main.js
|
||||||
|
@ -11,7 +11,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -288,11 +287,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
// data/
|
//
|
||||||
// foo.txt
|
// data/
|
||||||
// img/
|
// foo.txt
|
||||||
// a.png
|
// img/
|
||||||
// b.png
|
// a.png
|
||||||
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||||
|
@ -348,7 +349,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -46,7 +46,7 @@ func (r resource) loadFromBase(dir string) string {
|
||||||
|
|
||||||
fullpath := filepath.Join(dir, filename)
|
fullpath := filepath.Join(dir, filename)
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(fullpath)
|
b, err := os.ReadFile(fullpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fullpath + " failed with error: " + err.Error())
|
panic(fullpath + " failed with error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||||
|
|
||||||
//Package main generated by go-bindata.// sources:
|
// Package main generated by go-bindata.// sources:
|
||||||
// ../embedding-files-into-app/assets/css/main.css
|
// ../embedding-files-into-app/assets/css/main.css
|
||||||
// ../embedding-files-into-app/assets/favicon.ico
|
// ../embedding-files-into-app/assets/favicon.ico
|
||||||
// ../embedding-files-into-app/assets/js/main.js
|
// ../embedding-files-into-app/assets/js/main.js
|
||||||
|
@ -11,7 +11,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -288,11 +287,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
// data/
|
//
|
||||||
// foo.txt
|
// data/
|
||||||
// img/
|
// foo.txt
|
||||||
// a.png
|
// img/
|
||||||
// b.png
|
// a.png
|
||||||
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||||
|
@ -348,7 +349,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -48,7 +48,7 @@ func (r resource) loadFromBase(dir string) string {
|
||||||
|
|
||||||
fullpath := filepath.Join(dir, filename)
|
fullpath := filepath.Join(dir, filename)
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(fullpath)
|
b, err := os.ReadFile(fullpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fullpath + " failed with error: " + err.Error())
|
panic(fullpath + " failed with error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||||
|
|
||||||
//Package main generated by go-bindata.// sources:
|
// Package main generated by go-bindata.// sources:
|
||||||
// ../http2push/assets/app2/app2app3/css/main.css
|
// ../http2push/assets/app2/app2app3/css/main.css
|
||||||
// ../http2push/assets/app2/app2app3/dirs/dir1/text.txt
|
// ../http2push/assets/app2/app2app3/dirs/dir1/text.txt
|
||||||
// ../http2push/assets/app2/app2app3/dirs/dir2/text.txt
|
// ../http2push/assets/app2/app2app3/dirs/dir2/text.txt
|
||||||
|
@ -19,7 +19,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -464,11 +463,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
// data/
|
//
|
||||||
// foo.txt
|
// data/
|
||||||
// img/
|
// foo.txt
|
||||||
// a.png
|
// img/
|
||||||
// b.png
|
// a.png
|
||||||
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||||
|
@ -546,7 +547,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||||
|
|
||||||
//Package main generated by go-bindata.// sources:
|
// Package main generated by go-bindata.// sources:
|
||||||
// ../http2push/assets/app2/app2app3/css/main.css
|
// ../http2push/assets/app2/app2app3/css/main.css
|
||||||
// ../http2push/assets/app2/app2app3/dirs/dir1/text.txt
|
// ../http2push/assets/app2/app2app3/dirs/dir1/text.txt
|
||||||
// ../http2push/assets/app2/app2app3/dirs/dir2/text.txt
|
// ../http2push/assets/app2/app2app3/dirs/dir2/text.txt
|
||||||
|
@ -19,7 +19,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -464,11 +463,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
// data/
|
//
|
||||||
// foo.txt
|
// data/
|
||||||
// img/
|
// foo.txt
|
||||||
// a.png
|
// img/
|
||||||
// b.png
|
// a.png
|
||||||
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||||
|
@ -546,7 +547,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||||
|
|
||||||
//Package main generated by go-bindata.// sources:
|
// Package main generated by go-bindata.// sources:
|
||||||
// public/app.js
|
// public/app.js
|
||||||
// public/css/main.css
|
// public/css/main.css
|
||||||
// public/index.html
|
// public/index.html
|
||||||
|
@ -11,7 +11,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -288,11 +287,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
// data/
|
//
|
||||||
// foo.txt
|
// data/
|
||||||
// img/
|
// foo.txt
|
||||||
// a.png
|
// img/
|
||||||
// b.png
|
// a.png
|
||||||
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||||
|
@ -346,7 +347,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -310,11 +309,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
// data/
|
//
|
||||||
// foo.txt
|
// data/
|
||||||
// img/
|
// foo.txt
|
||||||
// a.png
|
// img/
|
||||||
// b.png
|
// a.png
|
||||||
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
||||||
|
@ -377,7 +378,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -41,7 +41,7 @@ func (r resource) loadFromBase(dir string) string {
|
||||||
|
|
||||||
fullpath := filepath.Join(dir, filename)
|
fullpath := filepath.Join(dir, filename)
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(fullpath)
|
b, err := os.ReadFile(fullpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fullpath + " failed with error: " + err.Error())
|
panic(fullpath + " failed with error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ func (r resource) loadFromBase(dir string) string {
|
||||||
|
|
||||||
fullpath := filepath.Join(dir, filename)
|
fullpath := filepath.Join(dir, filename)
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(fullpath)
|
b, err := os.ReadFile(fullpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fullpath + " failed with error: " + err.Error())
|
panic(fullpath + " failed with error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
/*Package main is a proxy + accesslog example.
|
/*
|
||||||
|
Package main is a proxy + accesslog example.
|
||||||
In this example we will make a small proxy which listens requests on "/proxy/+path".
|
In this example we will make a small proxy which listens requests on "/proxy/+path".
|
||||||
With two accesslog instances, one for the main application and one for the /proxy/ requests.
|
With two accesslog instances, one for the main application and one for the /proxy/ requests.
|
||||||
Of cource, you could a single accesslog for the whole application, but for the sake of the example
|
Of cource, you could a single accesslog for the whole application, but for the sake of the example
|
||||||
let's log them separately.
|
let's log them separately.
|
||||||
|
|
||||||
We will make use of iris.StripPrefix and host.ProxyHandler.*/
|
We will make use of iris.StripPrefix and host.ProxyHandler.
|
||||||
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -5,15 +5,15 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
pb "github.com/kataras/iris/v12/_examples/mvc/grpc-compatible/helloworld"
|
pb "github.com/kataras/iris/v12/_examples/mvc/grpc-compatible/helloworld"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
b, err := ioutil.ReadFile("../server.crt")
|
b, err := os.ReadFile("../server.crt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,14 +30,16 @@ type UsersController struct {
|
||||||
// curl -i -u admin:password http://localhost:8080/users
|
// curl -i -u admin:password http://localhost:8080/users
|
||||||
//
|
//
|
||||||
// The correct way if you have sensitive data:
|
// The correct way if you have sensitive data:
|
||||||
// func (c *UsersController) Get() (results []viewmodels.User) {
|
|
||||||
// data := c.Service.GetAll()
|
|
||||||
//
|
//
|
||||||
// for _, user := range data {
|
// func (c *UsersController) Get() (results []viewmodels.User) {
|
||||||
// results = append(results, viewmodels.User{user})
|
// data := c.Service.GetAll()
|
||||||
// }
|
//
|
||||||
// return
|
// for _, user := range data {
|
||||||
// }
|
// results = append(results, viewmodels.User{user})
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
// otherwise just return the datamodels.
|
// otherwise just return the datamodels.
|
||||||
func (c *UsersController) Get() (results []datamodels.User) {
|
func (c *UsersController) Get() (results []datamodels.User) {
|
||||||
return c.Service.GetAll()
|
return c.Service.GetAll()
|
||||||
|
|
|
@ -9,9 +9,11 @@ else as well, otherwise I am going with the first one:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// 1
|
// 1
|
||||||
mvc.Configure(app.Party("/user"), func(m *mvc.Application) {
|
|
||||||
m.Router.Use(cache.Handler(10*time.Second))
|
mvc.Configure(app.Party("/user"), func(m *mvc.Application) {
|
||||||
})
|
m.Router.Use(cache.Handler(10*time.Second))
|
||||||
|
})
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
@ -32,10 +34,12 @@ mvc.Configure(userRouter, ...)
|
||||||
```go
|
```go
|
||||||
// 4
|
// 4
|
||||||
// same:
|
// same:
|
||||||
app.PartyFunc("/user", func(r iris.Party){
|
|
||||||
r.Use(cache.Handler(10*time.Second))
|
app.PartyFunc("/user", func(r iris.Party){
|
||||||
mvc.Configure(r, ...)
|
r.Use(cache.Handler(10*time.Second))
|
||||||
})
|
mvc.Configure(r, ...)
|
||||||
|
})
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want to use a middleware for a single route,
|
If you want to use a middleware for a single route,
|
||||||
|
@ -48,16 +52,18 @@ then you just call it on the method:
|
||||||
var myMiddleware := myMiddleware.New(...) // this should return an iris/context.Handler
|
var myMiddleware := myMiddleware.New(...) // this should return an iris/context.Handler
|
||||||
|
|
||||||
type UserController struct{}
|
type UserController struct{}
|
||||||
func (c *UserController) GetSomething(ctx iris.Context) {
|
|
||||||
// ctx.Proceed checks if myMiddleware called `ctx.Next()`
|
|
||||||
// inside it and returns true if so, otherwise false.
|
|
||||||
nextCalled := ctx.Proceed(myMiddleware)
|
|
||||||
if !nextCalled {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// else do the job here, it's allowed
|
func (c *UserController) GetSomething(ctx iris.Context) {
|
||||||
}
|
// ctx.Proceed checks if myMiddleware called `ctx.Next()`
|
||||||
|
// inside it and returns true if so, otherwise false.
|
||||||
|
nextCalled := ctx.Proceed(myMiddleware)
|
||||||
|
if !nextCalled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// else do the job here, it's allowed
|
||||||
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
And last, if you want to add a middleware on a specific method
|
And last, if you want to add a middleware on a specific method
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
/*Package main shows how to add done handlers in an MVC application without
|
/*
|
||||||
|
Package main shows how to add done handlers in an MVC application without
|
||||||
the necessity of `ctx.Next()` inside the controller's methods.
|
the necessity of `ctx.Next()` inside the controller's methods.
|
||||||
|
|
||||||
When we want the `Done` handlers of that specific mvc app's `Party`
|
When we want the `Done` handlers of that specific mvc app's `Party`
|
||||||
to be executed but we don't want to add `ctx.Next()` on the `exampleController#EndRequest`*/
|
to be executed but we don't want to add `ctx.Next()` on the `exampleController#EndRequest`
|
||||||
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -28,42 +28,45 @@ func pong(ctx iris.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
+-------------------+
|
+-------------------+
|
||||||
| Env (DEV, PROD) |
|
| Env (DEV, PROD) |
|
||||||
+---------+---------+
|
+---------+---------+
|
||||||
| | |
|
| | |
|
||||||
| | |
|
| | |
|
||||||
| | |
|
| | |
|
||||||
DEV | | | PROD
|
DEV | | | PROD
|
||||||
|
|
||||||
-------------------+---------------------+ | +----------------------+-------------------
|
-------------------+---------------------+ | +----------------------+-------------------
|
||||||
| | |
|
|
||||||
| | |
|
| | |
|
||||||
+---+-----+ +----------------v------------------+ +----+----+
|
| | |
|
||||||
| sqlite | | NewDB(Env) DB | | mysql |
|
+---+-----+ +----------------v------------------+ +----+----+
|
||||||
+---+-----+ +----------------+---+--------------+ +----+----+
|
| sqlite | | NewDB(Env) DB | | mysql |
|
||||||
| | | |
|
+---+-----+ +----------------+---+--------------+ +----+----+
|
||||||
| | | |
|
| | | |
|
||||||
| | | |
|
| | | |
|
||||||
+--------------+-----+ +-------------------v---v-----------------+ +----+------+
|
| | | |
|
||||||
| greeterWithLogging | | NewGreetService(Env, DB) GreetService | | greeter |
|
+--------------+-----+ +-------------------v---v-----------------+ +----+------+
|
||||||
+--------------+-----+ +---------------------------+-------------+ +----+------+
|
| greeterWithLogging | | NewGreetService(Env, DB) GreetService | | greeter |
|
||||||
| | |
|
+--------------+-----+ +---------------------------+-------------+ +----+------+
|
||||||
| | |
|
| | |
|
||||||
| +-----------------------------------------+ |
|
| | |
|
||||||
| | GreetController | | |
|
| +-----------------------------------------+ |
|
||||||
| | | | |
|
| | GreetController | | |
|
||||||
| | - Service GreetService <-- | |
|
| | | | |
|
||||||
| | | |
|
| | - Service GreetService <-- | |
|
||||||
| +-------------------+---------------------+ |
|
| | | |
|
||||||
| | |
|
| +-------------------+---------------------+ |
|
||||||
| | |
|
| | |
|
||||||
| | |
|
| | |
|
||||||
| +-----------+-----------+ |
|
| | |
|
||||||
| | HTTP Request | |
|
| +-----------+-----------+ |
|
||||||
| +-----------------------+ |
|
| | HTTP Request | |
|
||||||
| | /greet?name=kataras | |
|
| +-----------------------+ |
|
||||||
| +-----------+-----------+ |
|
| | /greet?name=kataras | |
|
||||||
| | |
|
| +-----------+-----------+ |
|
||||||
|
| | |
|
||||||
|
|
||||||
+------------------+--------+ +------------+------------+ +-------+------------------+
|
+------------------+--------+ +------------+------------+ +-------+------------------+
|
||||||
| model.Response (JSON) | | Response (JSON, error) | | Bad Request |
|
| model.Response (JSON) | | Response (JSON, error) | | Bad Request |
|
||||||
+---------------------------+ +-------------------------+ +--------------------------+
|
+---------------------------+ +-------------------------+ +--------------------------+
|
||||||
|
|
|
@ -23,14 +23,16 @@ type MovieController struct {
|
||||||
// curl -i http://localhost:8080/movies
|
// curl -i http://localhost:8080/movies
|
||||||
//
|
//
|
||||||
// The correct way if you have sensitive data:
|
// The correct way if you have sensitive data:
|
||||||
// func (c *MovieController) Get() (results []viewmodels.Movie) {
|
|
||||||
// data := c.Service.GetAll()
|
|
||||||
//
|
//
|
||||||
// for _, movie := range data {
|
// func (c *MovieController) Get() (results []viewmodels.Movie) {
|
||||||
// results = append(results, viewmodels.Movie{movie})
|
// data := c.Service.GetAll()
|
||||||
// }
|
//
|
||||||
// return
|
// for _, movie := range data {
|
||||||
// }
|
// results = append(results, viewmodels.Movie{movie})
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
// otherwise just return the datamodels.
|
// otherwise just return the datamodels.
|
||||||
func (c *MovieController) Get() (results []datamodels.Movie) {
|
func (c *MovieController) Get() (results []datamodels.Movie) {
|
||||||
return c.Service.GetAll()
|
return c.Service.GetAll()
|
||||||
|
|
|
@ -18,7 +18,7 @@ func (srv *Server) buildRouter() {
|
||||||
ServerName: srv.config.ServerName,
|
ServerName: srv.config.ServerName,
|
||||||
Env: srv.config.Env,
|
Env: srv.config.Env,
|
||||||
Developer: "kataras",
|
Developer: "kataras",
|
||||||
TimeLocation: time.FixedZone("Greece/Athens", 10800),
|
TimeLocation: time.FixedZone("Greece/Athens", 7200),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
api := srv.Party("/api")
|
api := srv.Party("/api")
|
||||||
|
|
|
@ -8,7 +8,7 @@ func main() {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
|
||||||
app.Post("/", logAllBody, logJSON, logFormValues, func(ctx iris.Context) {
|
app.Post("/", logAllBody, logJSON, logFormValues, func(ctx iris.Context) {
|
||||||
// body, err := ioutil.ReadAll(ctx.Request().Body) once or
|
// body, err := io.ReadAll(ctx.Request().Body) once or
|
||||||
body, err := ctx.GetBody() // as many times as you need.
|
body, err := ctx.GetBody() // as many times as you need.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.StopWithError(iris.StatusInternalServerError, err)
|
ctx.StopWithError(iris.StatusInternalServerError, err)
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/kataras/iris/v12"
|
"github.com/kataras/iris/v12"
|
||||||
|
@ -69,7 +69,7 @@ func TestContentNegotiation(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rawResponse, err := ioutil.ReadAll(zr)
|
rawResponse, err := io.ReadAll(zr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,15 @@ import (
|
||||||
"github.com/kataras/iris/v12/core/router"
|
"github.com/kataras/iris/v12/core/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
/* A Router should contain all three of the following methods:
|
/*
|
||||||
- HandleRequest should handle the request based on the Context.
|
A Router should contain all three of the following methods:
|
||||||
HandleRequest(ctx iris.Context)
|
- HandleRequest should handle the request based on the Context.
|
||||||
- Build should builds the handler, it's being called on router's BuildRouter.
|
HandleRequest(ctx iris.Context)
|
||||||
Build(provider router.RoutesProvider) error
|
- Build should builds the handler, it's being called on router's BuildRouter.
|
||||||
- RouteExists reports whether a particular route exists.
|
Build(provider router.RoutesProvider) error
|
||||||
RouteExists(ctx iris.Context, method, path string) bool
|
- RouteExists reports whether a particular route exists.
|
||||||
- FireErrorCode(ctx iris.Context) should handle the given ctx.GetStatusCode().
|
RouteExists(ctx iris.Context, method, path string) bool
|
||||||
|
- FireErrorCode(ctx iris.Context) should handle the given ctx.GetStatusCode().
|
||||||
|
|
||||||
For a more detailed, complete and useful example
|
For a more detailed, complete and useful example
|
||||||
you can take a look at the iris' router itself which is located at:
|
you can take a look at the iris' router itself which is located at:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -29,7 +29,7 @@ func (r resource) loadFromBase(dir string) string {
|
||||||
|
|
||||||
fullpath := filepath.Join(dir, filename)
|
fullpath := filepath.Join(dir, filename)
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(fullpath)
|
b, err := os.ReadFile(fullpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fullpath + " failed with error: " + err.Error())
|
panic(fullpath + " failed with error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/*Package main is a simple example of the behavior change of the execution flow of the handlers,
|
/*
|
||||||
|
Package main is a simple example of the behavior change of the execution flow of the handlers,
|
||||||
normally we need the `ctx.Next()` to call the next handler in a route's handler chain,
|
normally we need the `ctx.Next()` to call the next handler in a route's handler chain,
|
||||||
but with the `ExecutionRules` we can change this default behavior.
|
but with the `ExecutionRules` we can change this default behavior.
|
||||||
Please read below before continue.
|
Please read below before continue.
|
||||||
|
@ -8,11 +9,11 @@ The `Party#SetExecutionRules` alters the execution flow of the route handlers.
|
||||||
For example, if for some reason the desired result is the (done or all) handlers
|
For example, if for some reason the desired result is the (done or all) handlers
|
||||||
to be executed no matter what, even if no `ctx.Next()` is called in the previous handlers:
|
to be executed no matter what, even if no `ctx.Next()` is called in the previous handlers:
|
||||||
|
|
||||||
app.SetExecutionRules(iris.ExecutionRules {
|
app.SetExecutionRules(iris.ExecutionRules {
|
||||||
Begin: iris.ExecutionOptions{Force: true}, # begin handlers(.Use)
|
Begin: iris.ExecutionOptions{Force: true}, # begin handlers(.Use)
|
||||||
Main: iris.ExecutionOptions{Force: true}, # main handler (.Handle/Get...)
|
Main: iris.ExecutionOptions{Force: true}, # main handler (.Handle/Get...)
|
||||||
Done: iris.ExecutionOptions{Force: true}, # done handlers (.Done)
|
Done: iris.ExecutionOptions{Force: true}, # done handlers (.Done)
|
||||||
})
|
})
|
||||||
|
|
||||||
Note that if `true` then the only remained way to "break" the handler chain
|
Note that if `true` then the only remained way to "break" the handler chain
|
||||||
is by calling the `ctx.StopExecution()` (now that `ctx.Next()` doesn't even matter).
|
is by calling the `ctx.StopExecution()` (now that `ctx.Next()` doesn't even matter).
|
||||||
|
@ -22,7 +23,6 @@ the same rules will be applied to that as well.
|
||||||
|
|
||||||
Reset of these rules to their defaults (before `Party#Handle`) can be done
|
Reset of these rules to their defaults (before `Party#Handle`) can be done
|
||||||
with `Party#SetExecutionRules(iris.ExecutionRules{})`.
|
with `Party#SetExecutionRules(iris.ExecutionRules{})`.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -14,7 +13,7 @@ import (
|
||||||
// The rest possible checks is up to you, take it as as an exercise!
|
// The rest possible checks is up to you, take it as as an exercise!
|
||||||
func TestURLShortener(t *testing.T) {
|
func TestURLShortener(t *testing.T) {
|
||||||
// temp db file
|
// temp db file
|
||||||
f, err := ioutil.TempFile("", "shortener")
|
f, err := os.CreateTemp("", "shortener")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("creating temp file for database failed: %v", err)
|
t.Fatalf("creating temp file for database failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||||
|
|
||||||
//Package main generated by go-bindata.// sources:
|
// Package main generated by go-bindata.// sources:
|
||||||
// templates/layouts/layout.html
|
// templates/layouts/layout.html
|
||||||
// templates/layouts/mylayout.html
|
// templates/layouts/mylayout.html
|
||||||
// templates/page1.html
|
// templates/page1.html
|
||||||
|
@ -12,7 +12,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -310,11 +309,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
// data/
|
//
|
||||||
// foo.txt
|
// data/
|
||||||
// img/
|
// foo.txt
|
||||||
// a.png
|
// img/
|
||||||
// b.png
|
// a.png
|
||||||
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||||
|
@ -371,7 +372,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -266,11 +265,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
// data/
|
//
|
||||||
// foo.txt
|
// data/
|
||||||
// img/
|
// foo.txt
|
||||||
// a.png
|
// img/
|
||||||
// b.png
|
// a.png
|
||||||
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
||||||
|
@ -323,7 +324,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -332,11 +331,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
// data/
|
//
|
||||||
// foo.txt
|
// data/
|
||||||
// img/
|
// foo.txt
|
||||||
// a.png
|
// img/
|
||||||
// b.png
|
// a.png
|
||||||
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
||||||
|
@ -394,7 +395,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -310,11 +309,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
// data/
|
//
|
||||||
// foo.txt
|
// data/
|
||||||
// img/
|
// foo.txt
|
||||||
// a.png
|
// img/
|
||||||
// b.png
|
// a.png
|
||||||
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
||||||
|
@ -371,7 +372,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -266,11 +265,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
// data/
|
//
|
||||||
// foo.txt
|
// data/
|
||||||
// img/
|
// foo.txt
|
||||||
// a.png
|
// img/
|
||||||
// b.png
|
// a.png
|
||||||
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
||||||
|
@ -321,7 +322,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -53,7 +52,7 @@ func readFileIfModified(lastMod time.Time) ([]byte, time.Time, error) {
|
||||||
if !fi.ModTime().After(lastMod) {
|
if !fi.ModTime().After(lastMod) {
|
||||||
return nil, lastMod, nil
|
return nil, lastMod, nil
|
||||||
}
|
}
|
||||||
p, err := ioutil.ReadFile(filename)
|
p, err := os.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fi.ModTime(), err
|
return nil, fi.ModTime(), err
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,12 +13,13 @@ import (
|
||||||
// The cases are filtered in order of their registration.
|
// The cases are filtered in order of their registration.
|
||||||
//
|
//
|
||||||
// Example Code:
|
// Example Code:
|
||||||
// switcher := Switch(Hosts{
|
//
|
||||||
// "mydomain.com": app,
|
// switcher := Switch(Hosts{
|
||||||
// "test.mydomain.com": testSubdomainApp,
|
// "mydomain.com": app,
|
||||||
// "otherdomain.com": "appName",
|
// "test.mydomain.com": testSubdomainApp,
|
||||||
// })
|
// "otherdomain.com": "appName",
|
||||||
// switcher.Listen(":80")
|
// })
|
||||||
|
// switcher.Listen(":80")
|
||||||
//
|
//
|
||||||
// Note that this is NOT an alternative for a load balancer.
|
// Note that this is NOT an alternative for a load balancer.
|
||||||
// The filters are executed by registration order and a matched Application
|
// The filters are executed by registration order and a matched Application
|
||||||
|
|
14
auth/auth.go
14
auth/auth.go
|
@ -99,6 +99,7 @@ func MustLoad[T User](filename string) *Auth[T] {
|
||||||
// Must is a helper that wraps a call to a function returning (*Auth[T], error)
|
// Must is a helper that wraps a call to a function returning (*Auth[T], error)
|
||||||
// and panics if the error is non-nil. It is intended for use in variable
|
// and panics if the error is non-nil. It is intended for use in variable
|
||||||
// initializations such as
|
// initializations such as
|
||||||
|
//
|
||||||
// var s = auth.Must(auth.New[MyUser](config))
|
// var s = auth.Must(auth.New[MyUser](config))
|
||||||
func Must[T User](s *Auth[T], err error) *Auth[T] {
|
func Must[T User](s *Auth[T], err error) *Auth[T] {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -142,12 +143,13 @@ func New[T User](config Configuration) (*Auth[T], error) {
|
||||||
// method when a Provider of T and ErrorHandler is available through the registered Party's dependencies.
|
// method when a Provider of T and ErrorHandler is available through the registered Party's dependencies.
|
||||||
//
|
//
|
||||||
// Usage Example:
|
// Usage Example:
|
||||||
// api := app.Party("/api")
|
//
|
||||||
// api.EnsureStaticBindings().RegisterDependency(
|
// api := app.Party("/api")
|
||||||
// NewAuthProviderErrorHandler(),
|
// api.EnsureStaticBindings().RegisterDependency(
|
||||||
// NewAuthCustomerProvider,
|
// NewAuthProviderErrorHandler(),
|
||||||
// auth.Must(auth.New[Customer](authConfig)).WithProviderAndErrorHandler,
|
// NewAuthCustomerProvider,
|
||||||
// )
|
// auth.Must(auth.New[Customer](authConfig)).WithProviderAndErrorHandler,
|
||||||
|
// )
|
||||||
func (s *Auth[T]) WithProviderAndErrorHandler(provider Provider[T], errHandler ErrorHandler) *Auth[T] {
|
func (s *Auth[T]) WithProviderAndErrorHandler(provider Provider[T], errHandler ErrorHandler) *Auth[T] {
|
||||||
if provider != nil {
|
if provider != nil {
|
||||||
for i := range s.providers {
|
for i := range s.providers {
|
||||||
|
|
9
cache/browser.go
vendored
9
cache/browser.go
vendored
|
@ -49,10 +49,11 @@ var NoCache = func(ctx *context.Context) {
|
||||||
// Usage: `app.Use(cache.StaticCache(24 * time.Hour))` or `app.Use(cache.Staticcache(-1))`.
|
// Usage: `app.Use(cache.StaticCache(24 * time.Hour))` or `app.Use(cache.Staticcache(-1))`.
|
||||||
// A middleware, which is a simple Handler can be called inside another handler as well, example:
|
// A middleware, which is a simple Handler can be called inside another handler as well, example:
|
||||||
// cacheMiddleware := cache.StaticCache(...)
|
// cacheMiddleware := cache.StaticCache(...)
|
||||||
// func(ctx iris.Context){
|
//
|
||||||
// cacheMiddleware(ctx)
|
// func(ctx iris.Context){
|
||||||
// [...]
|
// cacheMiddleware(ctx)
|
||||||
// }
|
// [...]
|
||||||
|
// }
|
||||||
var StaticCache = func(cacheDur time.Duration) context.Handler {
|
var StaticCache = func(cacheDur time.Duration) context.Handler {
|
||||||
if int64(cacheDur) <= 0 {
|
if int64(cacheDur) <= 0 {
|
||||||
return NoCache
|
return NoCache
|
||||||
|
|
6
cache/client/client.go
vendored
6
cache/client/client.go
vendored
|
@ -2,7 +2,7 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@ import (
|
||||||
// register one client handler per route.
|
// register one client handler per route.
|
||||||
//
|
//
|
||||||
// it's just calls a remote cache service server/handler,
|
// it's just calls a remote cache service server/handler,
|
||||||
// which lives on other, external machine.
|
|
||||||
//
|
//
|
||||||
|
// which lives on other, external machine.
|
||||||
type ClientHandler struct {
|
type ClientHandler struct {
|
||||||
// bodyHandler the original route's handler
|
// bodyHandler the original route's handler
|
||||||
bodyHandler context.Handler
|
bodyHandler context.Handler
|
||||||
|
@ -162,7 +162,7 @@ func (h *ClientHandler) ServeHTTP(ctx *context.Context) {
|
||||||
// get the status code , content type and the write the response body
|
// get the status code , content type and the write the response body
|
||||||
ctx.ContentType(response.Header.Get(cfg.ContentTypeHeader))
|
ctx.ContentType(response.Header.Get(cfg.ContentTypeHeader))
|
||||||
ctx.StatusCode(response.StatusCode)
|
ctx.StatusCode(response.StatusCode)
|
||||||
responseBody, err := ioutil.ReadAll(response.Body)
|
responseBody, err := io.ReadAll(response.Body)
|
||||||
response.Body.Close()
|
response.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|
13
cache/client/rule/validator.go
vendored
13
cache/client/rule/validator.go
vendored
|
@ -22,12 +22,13 @@ type PreValidator func(*context.Context) bool
|
||||||
//
|
//
|
||||||
// Q: What's the difference between this and a PreValidator?
|
// Q: What's the difference between this and a PreValidator?
|
||||||
// A: PreValidator runs BEFORE trying to get the cache, it cares only for the request
|
// A: PreValidator runs BEFORE trying to get the cache, it cares only for the request
|
||||||
// and if at least one PreValidator returns false then it just runs the original handler and stop there, at the other hand
|
//
|
||||||
// a PostValidator runs if all PreValidators returns true and original handler is executed but with a response recorder,
|
// and if at least one PreValidator returns false then it just runs the original handler and stop there, at the other hand
|
||||||
// also the PostValidator should return true to store the cached response.
|
// a PostValidator runs if all PreValidators returns true and original handler is executed but with a response recorder,
|
||||||
// Last, a PostValidator accepts a context
|
// also the PostValidator should return true to store the cached response.
|
||||||
// in order to be able to catch the original handler's response,
|
// Last, a PostValidator accepts a context
|
||||||
// the PreValidator checks only for request.
|
// in order to be able to catch the original handler's response,
|
||||||
|
// the PreValidator checks only for request.
|
||||||
//
|
//
|
||||||
// If a function of type of PostValidator returns true then the (shared-always) cache is allowed to be stored.
|
// If a function of type of PostValidator returns true then the (shared-always) cache is allowed to be stored.
|
||||||
type PostValidator func(*context.Context) bool
|
type PostValidator func(*context.Context) bool
|
||||||
|
|
|
@ -2,7 +2,6 @@ package iris
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -65,7 +64,7 @@ func parseYAML(filename string) (Configuration, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the raw contents of the file
|
// read the raw contents of the file
|
||||||
data, err := ioutil.ReadFile(yamlAbsPath)
|
data, err := os.ReadFile(yamlAbsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c, fmt.Errorf("parse yaml: %w", err)
|
return c, fmt.Errorf("parse yaml: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -112,7 +111,6 @@ func YAML(filename string) Configuration {
|
||||||
// Read more about toml's implementation at:
|
// Read more about toml's implementation at:
|
||||||
// https://github.com/toml-lang/toml
|
// https://github.com/toml-lang/toml
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// Accepts the absolute path of the configuration file.
|
// Accepts the absolute path of the configuration file.
|
||||||
// An error will be shown to the user via panic with the error message.
|
// An error will be shown to the user via panic with the error message.
|
||||||
// Error may occur when the file does not exist or is not formatted correctly.
|
// Error may occur when the file does not exist or is not formatted correctly.
|
||||||
|
@ -144,7 +142,7 @@ func TOML(filename string) Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the raw contents of the file
|
// read the raw contents of the file
|
||||||
data, err := ioutil.ReadFile(tomlAbsPath)
|
data, err := os.ReadFile(tomlAbsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("toml :%w", err))
|
panic(fmt.Errorf("toml :%w", err))
|
||||||
}
|
}
|
||||||
|
@ -754,6 +752,7 @@ type Configuration struct {
|
||||||
// then the application tries to optimize for the best performance where is possible.
|
// then the application tries to optimize for the best performance where is possible.
|
||||||
//
|
//
|
||||||
// Defaults to false.
|
// Defaults to false.
|
||||||
|
// Deprecated. As of version 12.2.x this field does nothing.
|
||||||
EnableOptimizations bool `ini:"enable_optimizations" json:"enableOptimizations,omitempty" yaml:"EnableOptimizations" toml:"EnableOptimizations"`
|
EnableOptimizations bool `ini:"enable_optimizations" json:"enableOptimizations,omitempty" yaml:"EnableOptimizations" toml:"EnableOptimizations"`
|
||||||
// EnableProtoJSON when this field is true
|
// EnableProtoJSON when this field is true
|
||||||
// enables the proto marshaler on given proto messages when calling the Context.JSON method.
|
// enables the proto marshaler on given proto messages when calling the Context.JSON method.
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package iris
|
package iris
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -103,7 +102,7 @@ func createGlobalConfiguration(t *testing.T) {
|
||||||
out, err := yaml.Marshal(&c)
|
out, err := yaml.Marshal(&c)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = ioutil.WriteFile(filename, out, os.FileMode(0666))
|
err = os.WriteFile(filename, out, os.FileMode(0666))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error while writing the global configuration field at: %s. Trace: %v\n", filename, err)
|
t.Fatalf("error while writing the global configuration field at: %s. Trace: %v\n", filename, err)
|
||||||
|
@ -131,7 +130,7 @@ func testConfigurationGlobal(t *testing.T, c Configurator) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigurationYAML(t *testing.T) {
|
func TestConfigurationYAML(t *testing.T) {
|
||||||
yamlFile, ferr := ioutil.TempFile("", "configuration.yml")
|
yamlFile, ferr := os.CreateTemp("", "configuration.yml")
|
||||||
|
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
t.Fatal(ferr)
|
t.Fatal(ferr)
|
||||||
|
@ -264,7 +263,7 @@ Other:
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigurationTOML(t *testing.T) {
|
func TestConfigurationTOML(t *testing.T) {
|
||||||
tomlFile, ferr := ioutil.TempFile("", "configuration.toml")
|
tomlFile, ferr := os.CreateTemp("", "configuration.toml")
|
||||||
|
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
t.Fatal(ferr)
|
t.Fatal(ferr)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -166,10 +166,12 @@ func (u *SimpleUser) GetField(key string) (interface{}, error) {
|
||||||
|
|
||||||
// UserMap can be used to convert a common map[string]interface{} to a User.
|
// UserMap can be used to convert a common map[string]interface{} to a User.
|
||||||
// Usage:
|
// Usage:
|
||||||
// user := map[string]interface{}{
|
//
|
||||||
// "username": "kataras",
|
// user := map[string]interface{}{
|
||||||
// "age" : 27,
|
// "username": "kataras",
|
||||||
// }
|
// "age" : 27,
|
||||||
|
// }
|
||||||
|
//
|
||||||
// ctx.SetUser(user)
|
// ctx.SetUser(user)
|
||||||
// OR
|
// OR
|
||||||
// user := UserStruct{....}
|
// user := UserStruct{....}
|
||||||
|
|
|
@ -275,7 +275,6 @@ type Filter func(*Context) bool
|
||||||
// Handlers here should act like middleware, they should contain `ctx.Next` to proceed
|
// Handlers here should act like middleware, they should contain `ctx.Next` to proceed
|
||||||
// to the next handler of the chain. Those "handlers" are registered to the per-request context.
|
// to the next handler of the chain. Those "handlers" are registered to the per-request context.
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// It checks the "filter" and if passed then
|
// It checks the "filter" and if passed then
|
||||||
// it, correctly, executes the "handlers".
|
// it, correctly, executes the "handlers".
|
||||||
//
|
//
|
||||||
|
|
|
@ -131,11 +131,12 @@ func (r *RequestParams) GetIntUnslashed(key string) (int, bool) {
|
||||||
// Key is the specific type, which should be unique.
|
// Key is the specific type, which should be unique.
|
||||||
// The value is a function which accepts the parameter index
|
// The value is a function which accepts the parameter index
|
||||||
// and it should return the value as the parameter type evaluator expects it.
|
// and it should return the value as the parameter type evaluator expects it.
|
||||||
// i.e [reflect.TypeOf("string")] = func(paramIndex int) interface{} {
|
//
|
||||||
// return func(ctx *Context) <T> {
|
// i.e [reflect.TypeOf("string")] = func(paramIndex int) interface{} {
|
||||||
// return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(<T>)
|
// return func(ctx *Context) <T> {
|
||||||
// }
|
// return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(<T>)
|
||||||
// }
|
// }
|
||||||
|
// }
|
||||||
//
|
//
|
||||||
// Read https://github.com/kataras/iris/tree/master/_examples/routing/macros for more details.
|
// Read https://github.com/kataras/iris/tree/master/_examples/routing/macros for more details.
|
||||||
// Checks for total available request parameters length
|
// Checks for total available request parameters length
|
||||||
|
@ -261,7 +262,9 @@ var ParamResolvers = map[reflect.Type]func(paramIndex int) interface{}{
|
||||||
// and the parameter's index based on the registered path.
|
// and the parameter's index based on the registered path.
|
||||||
// Usage: nameResolver := ParamResolverByKindAndKey(reflect.TypeOf(""), 0)
|
// Usage: nameResolver := ParamResolverByKindAndKey(reflect.TypeOf(""), 0)
|
||||||
// Inside a Handler: nameResolver.Call(ctx)[0]
|
// Inside a Handler: nameResolver.Call(ctx)[0]
|
||||||
// it will return the reflect.Value Of the exact type of the parameter(based on the path parameters and macros).
|
//
|
||||||
|
// it will return the reflect.Value Of the exact type of the parameter(based on the path parameters and macros).
|
||||||
|
//
|
||||||
// It is only useful for dynamic binding of the parameter, it is used on "hero" package and it should be modified
|
// It is only useful for dynamic binding of the parameter, it is used on "hero" package and it should be modified
|
||||||
// only when Macros are modified in such way that the default selections for the available go std types are not enough.
|
// only when Macros are modified in such way that the default selections for the available go std types are not enough.
|
||||||
//
|
//
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -32,7 +32,7 @@ func releaseResponseRecorder(w *ResponseRecorder) {
|
||||||
// A ResponseRecorder is used mostly for testing
|
// A ResponseRecorder is used mostly for testing
|
||||||
// in order to record and modify, if necessary, the body and status code and headers.
|
// in order to record and modify, if necessary, the body and status code and headers.
|
||||||
//
|
//
|
||||||
// See `context.Recorder`` method too.
|
// See `context.Recorder“ method too.
|
||||||
type ResponseRecorder struct {
|
type ResponseRecorder struct {
|
||||||
ResponseWriter
|
ResponseWriter
|
||||||
|
|
||||||
|
@ -366,7 +366,7 @@ func (w *ResponseRecorder) Result() *http.Response { // a modified copy of net/h
|
||||||
}
|
}
|
||||||
res.Status = fmt.Sprintf("%03d %s", res.StatusCode, http.StatusText(res.StatusCode))
|
res.Status = fmt.Sprintf("%03d %s", res.StatusCode, http.StatusText(res.StatusCode))
|
||||||
if w.chunks != nil {
|
if w.chunks != nil {
|
||||||
res.Body = ioutil.NopCloser(bytes.NewReader(w.chunks))
|
res.Body = io.NopCloser(bytes.NewReader(w.chunks))
|
||||||
} else {
|
} else {
|
||||||
res.Body = http.NoBody
|
res.Body = http.NoBody
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,6 @@ func StatusText(code int) string {
|
||||||
// Read more at `iris/Configuration#DisableAutoFireStatusCode` and
|
// Read more at `iris/Configuration#DisableAutoFireStatusCode` and
|
||||||
// `iris/core/router/Party#OnAnyErrorCode` for relative information.
|
// `iris/core/router/Party#OnAnyErrorCode` for relative information.
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// Modify this variable when your Iris server or/and client
|
// Modify this variable when your Iris server or/and client
|
||||||
// not follows the RFC: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
// not follows the RFC: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||||
var StatusCodeNotSuccessful = func(statusCode int) bool { return statusCode >= 400 }
|
var StatusCodeNotSuccessful = func(statusCode int) bool { return statusCode >= 400 }
|
||||||
|
|
|
@ -10,9 +10,10 @@ import (
|
||||||
// FromStd converts native http.Handler & http.HandlerFunc to context.Handler.
|
// FromStd converts native http.Handler & http.HandlerFunc to context.Handler.
|
||||||
//
|
//
|
||||||
// Supported form types:
|
// Supported form types:
|
||||||
// .FromStd(h http.Handler)
|
//
|
||||||
// .FromStd(func(w http.ResponseWriter, r *http.Request))
|
// .FromStd(h http.Handler)
|
||||||
// .FromStd(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc))
|
// .FromStd(func(w http.ResponseWriter, r *http.Request))
|
||||||
|
// .FromStd(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc))
|
||||||
func FromStd(handler interface{}) context.Handler {
|
func FromStd(handler interface{}) context.Handler {
|
||||||
switch h := handler.(type) {
|
switch h := handler.(type) {
|
||||||
case context.Handler:
|
case context.Handler:
|
||||||
|
|
|
@ -730,7 +730,6 @@ func (e Entry) Value() interface{} {
|
||||||
// Save same as `Set`
|
// Save same as `Set`
|
||||||
// However, if "immutable" is true then saves it as immutable (same as `SetImmutable`).
|
// However, if "immutable" is true then saves it as immutable (same as `SetImmutable`).
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// Returns the entry and true if it was just inserted, meaning that
|
// Returns the entry and true if it was just inserted, meaning that
|
||||||
// it will return the entry and a false boolean if the entry exists and it has been updated.
|
// it will return the entry and a false boolean if the entry exists and it has been updated.
|
||||||
func (r *Store) Save(key string, value interface{}, immutable bool) (Entry, bool) {
|
func (r *Store) Save(key string, value interface{}, immutable bool) (Entry, bool) {
|
||||||
|
|
|
@ -377,8 +377,9 @@ func (api *APIBuilder) RegisterDependency(dependencies ...interface{}) {
|
||||||
// (see ConfigureContainer().RegisterDependency)
|
// (see ConfigureContainer().RegisterDependency)
|
||||||
// or leave the framework to parse the request and fill the values accordingly.
|
// or leave the framework to parse the request and fill the values accordingly.
|
||||||
// The output of the "handlersFn" can be any output result:
|
// The output of the "handlersFn" can be any output result:
|
||||||
// custom structs <T>, string, []byte, int, error,
|
//
|
||||||
// a combination of the above, hero.Result(hero.View | hero.Response) and more.
|
// custom structs <T>, string, []byte, int, error,
|
||||||
|
// a combination of the above, hero.Result(hero.View | hero.Response) and more.
|
||||||
//
|
//
|
||||||
// If more than one handler function is registered
|
// If more than one handler function is registered
|
||||||
// then the execution happens without the nessecity of the `Context.Next` method,
|
// then the execution happens without the nessecity of the `Context.Next` method,
|
||||||
|
@ -390,22 +391,22 @@ func (api *APIBuilder) RegisterDependency(dependencies ...interface{}) {
|
||||||
// The client's request body and server's response body Go types.
|
// The client's request body and server's response body Go types.
|
||||||
// Could be any data structure.
|
// Could be any data structure.
|
||||||
//
|
//
|
||||||
// type (
|
// type (
|
||||||
// request struct {
|
// request struct {
|
||||||
// Firstname string `json:"firstname"`
|
// Firstname string `json:"firstname"`
|
||||||
// Lastname string `json:"lastname"`
|
// Lastname string `json:"lastname"`
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// response struct {
|
// response struct {
|
||||||
// ID uint64 `json:"id"`
|
// ID uint64 `json:"id"`
|
||||||
// Message string `json:"message"`
|
// Message string `json:"message"`
|
||||||
// }
|
// }
|
||||||
// )
|
// )
|
||||||
//
|
//
|
||||||
// Register the route hander.
|
// Register the route hander.
|
||||||
//
|
//
|
||||||
// HTTP VERB ROUTE PATH ROUTE HANDLER
|
// HTTP VERB ROUTE PATH ROUTE HANDLER
|
||||||
// app.HandleFunc("PUT", "/users/{id:uint64}", updateUser)
|
// app.HandleFunc("PUT", "/users/{id:uint64}", updateUser)
|
||||||
//
|
//
|
||||||
// Code the route handler function.
|
// Code the route handler function.
|
||||||
// Path parameters and request body are binded
|
// Path parameters and request body are binded
|
||||||
|
@ -413,26 +414,26 @@ func (api *APIBuilder) RegisterDependency(dependencies ...interface{}) {
|
||||||
// The "id" uint64 binds to "{id:uint64}" route path parameter and
|
// The "id" uint64 binds to "{id:uint64}" route path parameter and
|
||||||
// the "input" binds to client request data such as JSON.
|
// the "input" binds to client request data such as JSON.
|
||||||
//
|
//
|
||||||
// func updateUser(id uint64, input request) response {
|
// func updateUser(id uint64, input request) response {
|
||||||
// // [custom logic...]
|
// // [custom logic...]
|
||||||
//
|
//
|
||||||
// return response{
|
// return response{
|
||||||
// ID:id,
|
// ID:id,
|
||||||
// Message: "User updated successfully",
|
// Message: "User updated successfully",
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Simulate a client request which sends data
|
// Simulate a client request which sends data
|
||||||
// to the server and prints out the response.
|
// to the server and prints out the response.
|
||||||
//
|
//
|
||||||
// curl --request PUT -d '{"firstname":"John","lastname":"Doe"}' \
|
// curl --request PUT -d '{"firstname":"John","lastname":"Doe"}' \
|
||||||
// -H "Content-Type: application/json" \
|
// -H "Content-Type: application/json" \
|
||||||
// http://localhost:8080/users/42
|
// http://localhost:8080/users/42
|
||||||
//
|
//
|
||||||
// {
|
// {
|
||||||
// "id": 42,
|
// "id": 42,
|
||||||
// "message": "User updated successfully"
|
// "message": "User updated successfully"
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// See the `ConfigureContainer` for more features regrading
|
// See the `ConfigureContainer` for more features regrading
|
||||||
// the dependency injection, mvc and function handlers.
|
// the dependency injection, mvc and function handlers.
|
||||||
|
@ -474,11 +475,12 @@ func (api *APIBuilder) AllowMethods(methods ...string) Party {
|
||||||
// For example, if for some reason the desired result is the (done or all) handlers to be executed no matter what
|
// For example, if for some reason the desired result is the (done or all) handlers to be executed no matter what
|
||||||
// even if no `ctx.Next()` is called in the previous handlers, including the begin(`Use`),
|
// even if no `ctx.Next()` is called in the previous handlers, including the begin(`Use`),
|
||||||
// the main(`Handle`) and the done(`Done`) handlers themselves, then:
|
// the main(`Handle`) and the done(`Done`) handlers themselves, then:
|
||||||
// Party#SetExecutionRules(iris.ExecutionRules {
|
//
|
||||||
// Begin: iris.ExecutionOptions{Force: true},
|
// Party#SetExecutionRules(iris.ExecutionRules {
|
||||||
// Main: iris.ExecutionOptions{Force: true},
|
// Begin: iris.ExecutionOptions{Force: true},
|
||||||
// Done: iris.ExecutionOptions{Force: true},
|
// Main: iris.ExecutionOptions{Force: true},
|
||||||
// })
|
// Done: iris.ExecutionOptions{Force: true},
|
||||||
|
// })
|
||||||
//
|
//
|
||||||
// Note that if : true then the only remained way to "break" the handler chain is by `ctx.StopExecution()` now that `ctx.Next()` does not matter.
|
// Note that if : true then the only remained way to "break" the handler chain is by `ctx.StopExecution()` now that `ctx.Next()` does not matter.
|
||||||
//
|
//
|
||||||
|
@ -567,11 +569,14 @@ func (api *APIBuilder) handle(errorCode int, method string, relativePath string,
|
||||||
// otherwise use `Party` which can handle many paths with different handlers and middlewares.
|
// otherwise use `Party` which can handle many paths with different handlers and middlewares.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// app.HandleMany("GET", "/user /user/{id:uint64} /user/me", genericUserHandler)
|
//
|
||||||
|
// app.HandleMany("GET", "/user /user/{id:uint64} /user/me", genericUserHandler)
|
||||||
|
//
|
||||||
// At the other side, with `Handle` we've had to write:
|
// At the other side, with `Handle` we've had to write:
|
||||||
// app.Handle("GET", "/user", userHandler)
|
//
|
||||||
// app.Handle("GET", "/user/{id:uint64}", userByIDHandler)
|
// app.Handle("GET", "/user", userHandler)
|
||||||
// app.Handle("GET", "/user/me", userMeHandler)
|
// app.Handle("GET", "/user/{id:uint64}", userByIDHandler)
|
||||||
|
// app.Handle("GET", "/user/me", userMeHandler)
|
||||||
//
|
//
|
||||||
// app.HandleMany("GET POST", "/path", handler)
|
// app.HandleMany("GET POST", "/path", handler)
|
||||||
func (api *APIBuilder) HandleMany(methodOrMulti string, relativePathorMulti string, handlers ...context.Handler) (routes []*Route) {
|
func (api *APIBuilder) HandleMany(methodOrMulti string, relativePathorMulti string, handlers ...context.Handler) (routes []*Route) {
|
||||||
|
@ -606,7 +611,7 @@ func (api *APIBuilder) HandleMany(methodOrMulti string, relativePathorMulti stri
|
||||||
//
|
//
|
||||||
// Alternatively, to get just the handler for that look the FileServer function instead.
|
// Alternatively, to get just the handler for that look the FileServer function instead.
|
||||||
//
|
//
|
||||||
// api.HandleDir("/static", iris.Dir("./assets"), iris.DirOptions{IndexName: "/index.html", Compress: true})
|
// api.HandleDir("/static", iris.Dir("./assets"), iris.DirOptions{IndexName: "/index.html", Compress: true})
|
||||||
//
|
//
|
||||||
// Returns all the registered routes, including GET index and path patterm and HEAD.
|
// Returns all the registered routes, including GET index and path patterm and HEAD.
|
||||||
//
|
//
|
||||||
|
@ -904,12 +909,13 @@ func (api *APIBuilder) Party(relativePath string, handlers ...context.Handler) P
|
||||||
// Note: `iris#Party` and `core/router#Party` describes the exactly same interface.
|
// Note: `iris#Party` and `core/router#Party` describes the exactly same interface.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// app.PartyFunc("/users", func(u iris.Party){
|
//
|
||||||
// u.Use(authMiddleware, logMiddleware)
|
// app.PartyFunc("/users", func(u iris.Party){
|
||||||
// u.Get("/", getAllUsers)
|
// u.Use(authMiddleware, logMiddleware)
|
||||||
// u.Post("/", createOrUpdateUser)
|
// u.Get("/", getAllUsers)
|
||||||
// u.Delete("/", deleteUser)
|
// u.Post("/", createOrUpdateUser)
|
||||||
// })
|
// u.Delete("/", deleteUser)
|
||||||
|
// })
|
||||||
//
|
//
|
||||||
// Look `Party` for more.
|
// Look `Party` for more.
|
||||||
func (api *APIBuilder) PartyFunc(relativePath string, partyBuilderFunc func(p Party)) Party {
|
func (api *APIBuilder) PartyFunc(relativePath string, partyBuilderFunc func(p Party)) Party {
|
||||||
|
@ -949,16 +955,21 @@ type (
|
||||||
// Useful when the api's dependencies amount are too much to pass on a function.
|
// Useful when the api's dependencies amount are too much to pass on a function.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// app.PartyConfigure("/users", &api.UsersAPI{UserRepository: ..., ...})
|
//
|
||||||
|
// app.PartyConfigure("/users", &api.UsersAPI{UserRepository: ..., ...})
|
||||||
|
//
|
||||||
// Where UsersAPI looks like:
|
// Where UsersAPI looks like:
|
||||||
// type UsersAPI struct { [...] }
|
//
|
||||||
// func(api *UsersAPI) Configure(router iris.Party) {
|
// type UsersAPI struct { [...] }
|
||||||
// router.Get("/{id:uuid}", api.getUser)
|
// func(api *UsersAPI) Configure(router iris.Party) {
|
||||||
// [...]
|
// router.Get("/{id:uuid}", api.getUser)
|
||||||
// }
|
// [...]
|
||||||
|
// }
|
||||||
|
//
|
||||||
// Usage with (static) dependencies:
|
// Usage with (static) dependencies:
|
||||||
// app.RegisterDependency(userRepo, ...)
|
//
|
||||||
// app.PartyConfigure("/users", new(api.UsersAPI))
|
// app.RegisterDependency(userRepo, ...)
|
||||||
|
// app.PartyConfigure("/users", new(api.UsersAPI))
|
||||||
func (api *APIBuilder) PartyConfigure(relativePath string, partyReg ...PartyConfigurator) Party {
|
func (api *APIBuilder) PartyConfigure(relativePath string, partyReg ...PartyConfigurator) Party {
|
||||||
var child Party
|
var child Party
|
||||||
|
|
||||||
|
@ -1626,15 +1637,16 @@ func (api *APIBuilder) RegisterView(viewEngine context.ViewEngine) {
|
||||||
|
|
||||||
// FallbackView registers one or more fallback views for a template or a template layout.
|
// FallbackView registers one or more fallback views for a template or a template layout.
|
||||||
// Usage:
|
// Usage:
|
||||||
// FallbackView(iris.FallbackView("fallback.html"))
|
//
|
||||||
// FallbackView(iris.FallbackViewLayout("layouts/fallback.html"))
|
// FallbackView(iris.FallbackView("fallback.html"))
|
||||||
// OR
|
// FallbackView(iris.FallbackViewLayout("layouts/fallback.html"))
|
||||||
// FallbackView(iris.FallbackViewFunc(ctx iris.Context, err iris.ErrViewNotExist) error {
|
// OR
|
||||||
// err.Name is the previous template name.
|
// FallbackView(iris.FallbackViewFunc(ctx iris.Context, err iris.ErrViewNotExist) error {
|
||||||
// err.IsLayout reports whether the failure came from the layout template.
|
// err.Name is the previous template name.
|
||||||
// err.Data is the template data provided to the previous View call.
|
// err.IsLayout reports whether the failure came from the layout template.
|
||||||
// [...custom logic e.g. ctx.View("fallback", err.Data)]
|
// err.Data is the template data provided to the previous View call.
|
||||||
// })
|
// [...custom logic e.g. ctx.View("fallback", err.Data)]
|
||||||
|
// })
|
||||||
func (api *APIBuilder) FallbackView(provider context.FallbackViewProvider) {
|
func (api *APIBuilder) FallbackView(provider context.FallbackViewProvider) {
|
||||||
handler := func(ctx *context.Context) {
|
handler := func(ctx *context.Context) {
|
||||||
ctx.FallbackView(provider)
|
ctx.FallbackView(provider)
|
||||||
|
@ -1653,9 +1665,10 @@ func (api *APIBuilder) FallbackView(provider context.FallbackViewProvider) {
|
||||||
// app := iris.New()
|
// app := iris.New()
|
||||||
// app.RegisterView(iris.$VIEW_ENGINE("./views", ".$extension"))
|
// app.RegisterView(iris.$VIEW_ENGINE("./views", ".$extension"))
|
||||||
// my := app.Party("/my").Layout("layouts/mylayout.html")
|
// my := app.Party("/my").Layout("layouts/mylayout.html")
|
||||||
// my.Get("/", func(ctx iris.Context) {
|
//
|
||||||
// ctx.View("page1.html")
|
// my.Get("/", func(ctx iris.Context) {
|
||||||
// })
|
// ctx.View("page1.html")
|
||||||
|
// })
|
||||||
//
|
//
|
||||||
// Examples: https://github.com/kataras/iris/tree/master/_examples/view
|
// Examples: https://github.com/kataras/iris/tree/master/_examples/view
|
||||||
func (api *APIBuilder) Layout(tmplLayoutFile string) Party {
|
func (api *APIBuilder) Layout(tmplLayoutFile string) Party {
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"github.com/kataras/golog"
|
"github.com/kataras/golog"
|
||||||
)
|
)
|
||||||
|
|
||||||
//
|
|
||||||
// randStringBytesMaskImprSrc helps us to generate random paths for the test,
|
// randStringBytesMaskImprSrc helps us to generate random paths for the test,
|
||||||
// the below piece of code is external, as an answer to a stackoverflow question.
|
// the below piece of code is external, as an answer to a stackoverflow question.
|
||||||
//
|
//
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"html"
|
"html"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
@ -1041,7 +1040,7 @@ func cacheFiles(ctx stdContext.Context, fs http.FileSystem, names []string, comp
|
||||||
|
|
||||||
fi := newFileInfo(path.Base(name), inf.Mode(), inf.ModTime())
|
fi := newFileInfo(path.Base(name), inf.Mode(), inf.ModTime())
|
||||||
|
|
||||||
contents, err := ioutil.ReadAll(f)
|
contents, err := io.ReadAll(f)
|
||||||
f.Close()
|
f.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -6,9 +6,10 @@ import (
|
||||||
|
|
||||||
// ExecutionRules gives control to the execution of the route handlers outside of the handlers themselves.
|
// ExecutionRules gives control to the execution of the route handlers outside of the handlers themselves.
|
||||||
// Usage:
|
// Usage:
|
||||||
// Party#SetExecutionRules(ExecutionRules {
|
//
|
||||||
// Done: ExecutionOptions{Force: true},
|
// Party#SetExecutionRules(ExecutionRules {
|
||||||
// })
|
// Done: ExecutionOptions{Force: true},
|
||||||
|
// })
|
||||||
//
|
//
|
||||||
// See `Party#SetExecutionRules` for more.
|
// See `Party#SetExecutionRules` for more.
|
||||||
type ExecutionRules struct {
|
type ExecutionRules struct {
|
||||||
|
|
|
@ -560,9 +560,9 @@ func init() {
|
||||||
// system's mime.types file(s) if available under one or more of these
|
// system's mime.types file(s) if available under one or more of these
|
||||||
// names:
|
// names:
|
||||||
//
|
//
|
||||||
// /etc/mime.types
|
// /etc/mime.types
|
||||||
// /etc/apache2/mime.types
|
// /etc/apache2/mime.types
|
||||||
// /etc/apache/mime.types
|
// /etc/apache/mime.types
|
||||||
//
|
//
|
||||||
// On Windows, MIME types are extracted from the registry.
|
// On Windows, MIME types are extracted from the registry.
|
||||||
//
|
//
|
||||||
|
|
|
@ -491,8 +491,9 @@ func (r *Route) GetTitle() string {
|
||||||
// Should be called after `Build` state.
|
// Should be called after `Build` state.
|
||||||
//
|
//
|
||||||
// It prints the @method: @path (@description) (@route_rel_location)
|
// It prints the @method: @path (@description) (@route_rel_location)
|
||||||
// * @handler_name (@handler_rel_location)
|
// - @handler_name (@handler_rel_location)
|
||||||
// * @second_handler ...
|
// - @second_handler ...
|
||||||
|
//
|
||||||
// If route and handler line:number locations are equal then the second is ignored.
|
// If route and handler line:number locations are equal then the second is ignored.
|
||||||
func (r *Route) Trace(w io.Writer, stoppedIndex int) {
|
func (r *Route) Trace(w io.Writer, stoppedIndex int) {
|
||||||
title := r.GetTitle()
|
title := r.GetTitle()
|
||||||
|
|
21
doc.go
21
doc.go
|
@ -34,34 +34,33 @@ Easy to learn for new gophers and advanced features for experienced, it goes as
|
||||||
|
|
||||||
Source code and other details for the project are available at GitHub:
|
Source code and other details for the project are available at GitHub:
|
||||||
|
|
||||||
https://github.com/kataras/iris
|
https://github.com/kataras/iris
|
||||||
|
|
||||||
Current Version
|
# Current Version
|
||||||
|
|
||||||
12.2.0-beta3
|
12.2.0-beta4
|
||||||
|
|
||||||
Installation
|
# Installation
|
||||||
|
|
||||||
The only requirement is the Go Programming Language, at least version 1.18.
|
The only requirement is the Go Programming Language, at least version 1.18.
|
||||||
|
|
||||||
$ go get github.com/kataras/iris/v12@master
|
$ go get github.com/kataras/iris/v12@master
|
||||||
|
|
||||||
Wiki:
|
Wiki:
|
||||||
|
|
||||||
https://github.com/kataras/iris/wiki
|
https://github.com/kataras/iris/wiki
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
https://github.com/kataras/iris/tree/master/_examples
|
https://github.com/kataras/iris/tree/master/_examples
|
||||||
|
|
||||||
Middleware:
|
Middleware:
|
||||||
|
|
||||||
https://github.com/kataras/iris/tree/master/middleware
|
https://github.com/kataras/iris/tree/master/middleware
|
||||||
https://github.com/iris-contrib/middleware
|
https://github.com/iris-contrib/middleware
|
||||||
|
|
||||||
Home Page:
|
Home Page:
|
||||||
|
|
||||||
https://iris-go.com
|
https://iris-go.com
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package iris
|
package iris
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -15,7 +15,6 @@ require (
|
||||||
github.com/fatih/structs v1.1.0
|
github.com/fatih/structs v1.1.0
|
||||||
github.com/flosch/pongo2/v4 v4.0.2
|
github.com/flosch/pongo2/v4 v4.0.2
|
||||||
github.com/go-redis/redis/v8 v8.11.5
|
github.com/go-redis/redis/v8 v8.11.5
|
||||||
github.com/goccy/go-json v0.9.8-0.20220506185958-23bd66f4c0d5
|
|
||||||
github.com/golang/snappy v0.0.4
|
github.com/golang/snappy v0.0.4
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/gorilla/securecookie v1.1.1
|
github.com/gorilla/securecookie v1.1.1
|
||||||
|
|
2
go.sum
generated
2
go.sum
generated
|
@ -62,8 +62,6 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||||
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
|
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
|
||||||
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
|
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
|
||||||
github.com/goccy/go-json v0.9.8-0.20220506185958-23bd66f4c0d5 h1:aeyOtISssR4sP36FAC9LV96PQqxzcbhz54EWv9U+ZGc=
|
|
||||||
github.com/goccy/go-json v0.9.8-0.20220506185958-23bd66f4c0d5/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
|
|
|
@ -326,23 +326,28 @@ func Handler(fn interface{}) context.Handler {
|
||||||
// It returns a standard `iris/context.Handler` which can be used anywhere in an Iris Application,
|
// It returns a standard `iris/context.Handler` which can be used anywhere in an Iris Application,
|
||||||
// as middleware or as simple route handler or subdomain's handler.
|
// as middleware or as simple route handler or subdomain's handler.
|
||||||
//
|
//
|
||||||
// func(...<T>) iris.Handler
|
// func(...<T>) iris.Handler
|
||||||
|
//
|
||||||
// - if <T> are all static dependencies then
|
// - if <T> are all static dependencies then
|
||||||
// there is no reflection involved at serve-time.
|
// there is no reflection involved at serve-time.
|
||||||
//
|
//
|
||||||
// func(pathParameter string, ...<T>)
|
// func(pathParameter string, ...<T>)
|
||||||
|
//
|
||||||
// - one or more path parameters (e.g. :uid, :string, :int, :path, :uint64)
|
// - one or more path parameters (e.g. :uid, :string, :int, :path, :uint64)
|
||||||
// are automatically binded to the first input Go standard types (string, int, uint64 and e.t.c.)
|
// are automatically binded to the first input Go standard types (string, int, uint64 and e.t.c.)
|
||||||
//
|
//
|
||||||
// func(<T>) error
|
// func(<T>) error
|
||||||
|
//
|
||||||
// - if a function returns an error then this error's text is sent to the client automatically.
|
// - if a function returns an error then this error's text is sent to the client automatically.
|
||||||
//
|
//
|
||||||
// func(<T>) <R>
|
// func(<T>) <R>
|
||||||
|
//
|
||||||
// - The result of the function is a dependency too.
|
// - The result of the function is a dependency too.
|
||||||
// If <R> is a request-scope dependency (dynamic) then
|
// If <R> is a request-scope dependency (dynamic) then
|
||||||
// this function will be called at every request.
|
// this function will be called at every request.
|
||||||
//
|
//
|
||||||
// func(<T>) <R>
|
// func(<T>) <R>
|
||||||
|
//
|
||||||
// - If <R> is static dependency (e.g. a database or a service) then its result
|
// - If <R> is static dependency (e.g. a database or a service) then its result
|
||||||
// can be used as a static dependency to the next dependencies or to the controller/function itself.
|
// can be used as a static dependency to the next dependencies or to the controller/function itself.
|
||||||
func (c *Container) Handler(fn interface{}) context.Handler {
|
func (c *Container) Handler(fn interface{}) context.Handler {
|
||||||
|
|
|
@ -27,11 +27,9 @@ func defaultResultHandler(ctx *context.Context, v interface{}) error {
|
||||||
|
|
||||||
switch context.TrimHeaderValue(ctx.GetContentType()) {
|
switch context.TrimHeaderValue(ctx.GetContentType()) {
|
||||||
case context.ContentXMLHeaderValue, context.ContentXMLUnreadableHeaderValue:
|
case context.ContentXMLHeaderValue, context.ContentXMLUnreadableHeaderValue:
|
||||||
_, err := ctx.XML(v)
|
return ctx.XML(v)
|
||||||
return err
|
|
||||||
case context.ContentYAMLHeaderValue:
|
case context.ContentYAMLHeaderValue:
|
||||||
_, err := ctx.YAML(v)
|
return ctx.YAML(v)
|
||||||
return err
|
|
||||||
case context.ContentProtobufHeaderValue:
|
case context.ContentProtobufHeaderValue:
|
||||||
msg, ok := v.(proto.Message)
|
msg, ok := v.(proto.Message)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -45,8 +43,7 @@ func defaultResultHandler(ctx *context.Context, v interface{}) error {
|
||||||
return err
|
return err
|
||||||
default:
|
default:
|
||||||
// otherwise default to JSON.
|
// otherwise default to JSON.
|
||||||
_, err := ctx.JSON(v)
|
return ctx.JSON(v)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ func (e err) Dispatch(ctx iris.Context) {
|
||||||
// write the status code based on the err's StatusCode.
|
// write the status code based on the err's StatusCode.
|
||||||
ctx.StatusCode(e.Status)
|
ctx.StatusCode(e.Status)
|
||||||
// send to the client the whole object as json
|
// send to the client the whole object as json
|
||||||
_, _ = ctx.JSON(e)
|
_ = ctx.JSON(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCustomErrorAsDispatcher() err {
|
func GetCustomErrorAsDispatcher() err {
|
||||||
|
|
|
@ -98,9 +98,12 @@ func DefaultConfiguration() *Configuration {
|
||||||
|
|
||||||
// New Prepares and returns a new test framework based on the "app".
|
// New Prepares and returns a new test framework based on the "app".
|
||||||
// Usage:
|
// Usage:
|
||||||
// httptest.New(t, app)
|
//
|
||||||
|
// httptest.New(t, app)
|
||||||
|
//
|
||||||
// With options:
|
// With options:
|
||||||
// httptest.New(t, app, httptest.URL(...), httptest.Debug(true), httptest.LogLevel("debug"), httptest.Strict(true))
|
//
|
||||||
|
// httptest.New(t, app, httptest.URL(...), httptest.Debug(true), httptest.LogLevel("debug"), httptest.Strict(true))
|
||||||
//
|
//
|
||||||
// Example at: https://github.com/kataras/iris/tree/master/_examples/testing/httptest.
|
// Example at: https://github.com/kataras/iris/tree/master/_examples/testing/httptest.
|
||||||
func New(t *testing.T, app *iris.Application, setters ...OptionSetter) *httpexpect.Expect {
|
func New(t *testing.T, app *iris.Application, setters ...OptionSetter) *httpexpect.Expect {
|
||||||
|
|
|
@ -152,7 +152,7 @@ func (loc *Locale) Tag() *language.Tag {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Language should return the exact languagecode of this `Locale`
|
// Language should return the exact languagecode of this `Locale`
|
||||||
//that the user provided on `New` function.
|
// that the user provided on `New` function.
|
||||||
//
|
//
|
||||||
// Same as `Tag().String()` but it's static.
|
// Same as `Tag().String()` but it's static.
|
||||||
func (loc *Locale) Language() string {
|
func (loc *Locale) Language() string {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package i18n
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ func Glob(globPattern string, options LoaderConfig) Loader {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return load(assetNames, ioutil.ReadFile, options)
|
return load(assetNames, os.ReadFile, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assets accepts a function that returns a list of filenames (physical or virtual),
|
// Assets accepts a function that returns a list of filenames (physical or virtual),
|
||||||
|
|
20
iris.go
20
iris.go
|
@ -299,6 +299,7 @@ func (app *Application) ConfigurationReadOnly() context.ConfigurationReadOnly {
|
||||||
// Adding one or more outputs : app.Logger().AddOutput(io.Writer...)
|
// Adding one or more outputs : app.Logger().AddOutput(io.Writer...)
|
||||||
//
|
//
|
||||||
// Adding custom levels requires import of the `github.com/kataras/golog` package:
|
// Adding custom levels requires import of the `github.com/kataras/golog` package:
|
||||||
|
//
|
||||||
// First we create our level to a golog.Level
|
// First we create our level to a golog.Level
|
||||||
// in order to be used in the Log functions.
|
// in order to be used in the Log functions.
|
||||||
// var SuccessLevel golog.Level = 6
|
// var SuccessLevel golog.Level = 6
|
||||||
|
@ -309,6 +310,7 @@ func (app *Application) ConfigurationReadOnly() context.ConfigurationReadOnly {
|
||||||
// // ColorfulText (Green Color[SUCC])
|
// // ColorfulText (Green Color[SUCC])
|
||||||
// ColorfulText: "\x1b[32m[SUCC]\x1b[0m",
|
// ColorfulText: "\x1b[32m[SUCC]\x1b[0m",
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// app.Logger().SetLevel("success")
|
// app.Logger().SetLevel("success")
|
||||||
// app.Logger().Logf(SuccessLevel, "a custom leveled log message")
|
// app.Logger().Logf(SuccessLevel, "a custom leveled log message")
|
||||||
|
@ -437,12 +439,12 @@ func (app *Application) GetContextPool() *context.Pool {
|
||||||
//
|
//
|
||||||
// ExampleCode:
|
// ExampleCode:
|
||||||
//
|
//
|
||||||
// type contextErrorHandler struct{}
|
// type contextErrorHandler struct{}
|
||||||
// func (e *contextErrorHandler) HandleContextError(ctx iris.Context, err error) {
|
// func (e *contextErrorHandler) HandleContextError(ctx iris.Context, err error) {
|
||||||
// errors.InvalidArgument.Err(ctx, err)
|
// errors.InvalidArgument.Err(ctx, err)
|
||||||
// }
|
// }
|
||||||
// ...
|
// ...
|
||||||
// app.SetContextErrorHandler(new(contextErrorHandler))
|
// app.SetContextErrorHandler(new(contextErrorHandler))
|
||||||
func (app *Application) SetContextErrorHandler(errHandler context.ErrorHandler) *Application {
|
func (app *Application) SetContextErrorHandler(errHandler context.ErrorHandler) *Application {
|
||||||
app.contextErrorHandler = errHandler
|
app.contextErrorHandler = errHandler
|
||||||
return app
|
return app
|
||||||
|
@ -653,9 +655,9 @@ func (app *Application) Shutdown(ctx stdContext.Context) error {
|
||||||
//
|
//
|
||||||
// import "github.com/kataras/iris/v12/core/errgroup"
|
// import "github.com/kataras/iris/v12/core/errgroup"
|
||||||
//
|
//
|
||||||
// errgroup.Walk(app.Build(), func(typ interface{}, err error) {
|
// errgroup.Walk(app.Build(), func(typ interface{}, err error) {
|
||||||
// app.Logger().Errorf("%s: %s", typ, err)
|
// app.Logger().Errorf("%s: %s", typ, err)
|
||||||
// })
|
// })
|
||||||
func (app *Application) Build() error {
|
func (app *Application) Build() error {
|
||||||
if app.builded {
|
if app.builded {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -237,7 +237,7 @@ type (
|
||||||
Step3 interface {
|
Step3 interface {
|
||||||
// Health enables the /health route.
|
// Health enables the /health route.
|
||||||
// If "env" and "developer" are given, these fields will be populated to the client
|
// If "env" and "developer" are given, these fields will be populated to the client
|
||||||
// through headers and environemnt on health route.
|
// through headers and environment on health route.
|
||||||
Health(b bool, env, developer string) Step4
|
Health(b bool, env, developer string) Step4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,9 @@ import (
|
||||||
// Note that the builtin macros return error too, but they're handled
|
// Note that the builtin macros return error too, but they're handled
|
||||||
// by the `else` literal (error code). To change this behavior
|
// by the `else` literal (error code). To change this behavior
|
||||||
// and send a custom error response you have to register it:
|
// and send a custom error response you have to register it:
|
||||||
// app.Macros().Get("uuid").HandleError(func(ctx iris.Context, paramIndex int, err error)).
|
//
|
||||||
|
// app.Macros().Get("uuid").HandleError(func(ctx iris.Context, paramIndex int, err error)).
|
||||||
|
//
|
||||||
// You can also set custom macros by `app.Macros().Register`.
|
// You can also set custom macros by `app.Macros().Register`.
|
||||||
//
|
//
|
||||||
// See macro.HandleError to set it.
|
// See macro.HandleError to set it.
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -324,7 +323,7 @@ func BenchmarkAccessLogAfterPrint(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func benchmarkAccessLogAfter(b *testing.B, withLogStruct, async bool) {
|
func benchmarkAccessLogAfter(b *testing.B, withLogStruct, async bool) {
|
||||||
ac := New(ioutil.Discard)
|
ac := New(io.Discard)
|
||||||
ac.Clock = TClock(time.Time{})
|
ac.Clock = TClock(time.Time{})
|
||||||
ac.BytesReceived = false
|
ac.BytesReceived = false
|
||||||
ac.BytesReceivedBody = false
|
ac.BytesReceivedBody = false
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Log represents the log data specifically for the accesslog middleware.
|
// Log represents the log data specifically for the accesslog middleware.
|
||||||
|
//
|
||||||
//easyjson:json
|
//easyjson:json
|
||||||
type Log struct {
|
type Log struct {
|
||||||
// The AccessLog instance this Log was created of.
|
// The AccessLog instance this Log was created of.
|
||||||
|
|
|
@ -52,8 +52,9 @@ type ErrorHandler func(ctx *context.Context, err error)
|
||||||
// The only required value is the Allow field.
|
// The only required value is the Allow field.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// opts := Options { ... }
|
//
|
||||||
// auth := New(opts)
|
// opts := Options { ... }
|
||||||
|
// auth := New(opts)
|
||||||
type Options struct {
|
type Options struct {
|
||||||
// Realm directive, read http://tools.ietf.org/html/rfc2617#section-1.2 for details.
|
// Realm directive, read http://tools.ietf.org/html/rfc2617#section-1.2 for details.
|
||||||
// E.g. "Authorization Required".
|
// E.g. "Authorization Required".
|
||||||
|
@ -171,17 +172,18 @@ type BasicAuth struct {
|
||||||
// The result should be used to wrap an existing handler or the HTTP application's root router.
|
// The result should be used to wrap an existing handler or the HTTP application's root router.
|
||||||
//
|
//
|
||||||
// Example Code:
|
// Example Code:
|
||||||
// opts := basicauth.Options{
|
//
|
||||||
// Realm: basicauth.DefaultRealm,
|
// opts := basicauth.Options{
|
||||||
// ErrorHandler: basicauth.DefaultErrorHandler,
|
// Realm: basicauth.DefaultRealm,
|
||||||
// MaxAge: 2 * time.Hour,
|
// ErrorHandler: basicauth.DefaultErrorHandler,
|
||||||
// GC: basicauth.GC{
|
// MaxAge: 2 * time.Hour,
|
||||||
// Every: 3 * time.Hour,
|
// GC: basicauth.GC{
|
||||||
// },
|
// Every: 3 * time.Hour,
|
||||||
// Allow: basicauth.AllowUsers(users),
|
// },
|
||||||
// }
|
// Allow: basicauth.AllowUsers(users),
|
||||||
// auth := basicauth.New(opts)
|
// }
|
||||||
// app.Use(auth)
|
// auth := basicauth.New(opts)
|
||||||
|
// app.Use(auth)
|
||||||
//
|
//
|
||||||
// Access the user in the route handler with: ctx.User().GetRaw().(*myCustomType).
|
// Access the user in the route handler with: ctx.User().GetRaw().(*myCustomType).
|
||||||
//
|
//
|
||||||
|
@ -238,16 +240,18 @@ func New(opts Options) context.Handler {
|
||||||
// are required as they are compared against the user input
|
// are required as they are compared against the user input
|
||||||
// when access to protected resource is requested.
|
// when access to protected resource is requested.
|
||||||
// A user list can defined with one of the following values:
|
// A user list can defined with one of the following values:
|
||||||
// map[string]string form of: {username:password, ...}
|
//
|
||||||
// map[string]interface{} form of: {"username": {"password": "...", "other_field": ...}, ...}
|
// map[string]string form of: {username:password, ...}
|
||||||
// []T which T completes the User interface, where T is a struct value
|
// map[string]interface{} form of: {"username": {"password": "...", "other_field": ...}, ...}
|
||||||
// []T which T contains at least Username and Password fields.
|
// []T which T completes the User interface, where T is a struct value
|
||||||
|
// []T which T contains at least Username and Password fields.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// auth := Default(map[string]string{
|
//
|
||||||
// "admin": "admin",
|
// auth := Default(map[string]string{
|
||||||
// "john": "p@ss",
|
// "admin": "admin",
|
||||||
// })
|
// "john": "p@ss",
|
||||||
|
// })
|
||||||
func Default(users interface{}, userOpts ...UserAuthOption) context.Handler {
|
func Default(users interface{}, userOpts ...UserAuthOption) context.Handler {
|
||||||
opts := Options{
|
opts := Options{
|
||||||
Realm: DefaultRealm,
|
Realm: DefaultRealm,
|
||||||
|
@ -260,7 +264,8 @@ func Default(users interface{}, userOpts ...UserAuthOption) context.Handler {
|
||||||
// a filename to load the users from.
|
// a filename to load the users from.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// auth := Load("users.yml")
|
//
|
||||||
|
// auth := Load("users.yml")
|
||||||
func Load(jsonOrYamlFilename string, userOpts ...UserAuthOption) context.Handler {
|
func Load(jsonOrYamlFilename string, userOpts ...UserAuthOption) context.Handler {
|
||||||
opts := Options{
|
opts := Options{
|
||||||
Realm: DefaultRealm,
|
Realm: DefaultRealm,
|
||||||
|
|
|
@ -3,7 +3,7 @@ package basicauth
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -16,8 +16,8 @@ import (
|
||||||
// ReadFile can be used to customize the way the
|
// ReadFile can be used to customize the way the
|
||||||
// AllowUsersFile function is loading the filename from.
|
// AllowUsersFile function is loading the filename from.
|
||||||
// Example of usage: embedded users.yml file.
|
// Example of usage: embedded users.yml file.
|
||||||
// Defaults to the `ioutil.ReadFile` which reads the file from the physical disk.
|
// Defaults to the `os.ReadFile` which reads the file from the physical disk.
|
||||||
var ReadFile = ioutil.ReadFile
|
var ReadFile = os.ReadFile
|
||||||
|
|
||||||
// User is a partial part of the iris.User interface.
|
// User is a partial part of the iris.User interface.
|
||||||
// It's used to declare a static slice of registered User for authentication.
|
// It's used to declare a static slice of registered User for authentication.
|
||||||
|
@ -48,10 +48,11 @@ type UserAuthOption func(*UserAuthOptions)
|
||||||
// See https://www.usenix.org/legacy/event/usenix99/provos/provos.pdf.
|
// See https://www.usenix.org/legacy/event/usenix99/provos/provos.pdf.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// Default(..., BCRYPT) OR
|
//
|
||||||
// Load(..., BCRYPT) OR
|
// Default(..., BCRYPT) OR
|
||||||
// Options.Allow = AllowUsers(..., BCRYPT) OR
|
// Load(..., BCRYPT) OR
|
||||||
// OPtions.Allow = AllowUsersFile(..., BCRYPT)
|
// Options.Allow = AllowUsers(..., BCRYPT) OR
|
||||||
|
// OPtions.Allow = AllowUsersFile(..., BCRYPT)
|
||||||
func BCRYPT(opts *UserAuthOptions) {
|
func BCRYPT(opts *UserAuthOptions) {
|
||||||
opts.ComparePassword = func(stored, userPassword string) bool {
|
opts.ComparePassword = func(stored, userPassword string) bool {
|
||||||
err := bcrypt.CompareHashAndPassword([]byte(stored), []byte(userPassword))
|
err := bcrypt.CompareHashAndPassword([]byte(stored), []byte(userPassword))
|
||||||
|
@ -75,10 +76,11 @@ func toUserAuthOptions(opts []UserAuthOption) (options UserAuthOptions) {
|
||||||
|
|
||||||
// AllowUsers is an AuthFunc which authenticates user input based on a (static) user list.
|
// AllowUsers is an AuthFunc which authenticates user input based on a (static) user list.
|
||||||
// The "users" input parameter can be one of the following forms:
|
// The "users" input parameter can be one of the following forms:
|
||||||
// map[string]string e.g. {username: password, username: password...}.
|
//
|
||||||
// []map[string]interface{} e.g. []{"username": "...", "password": "...", "other_field": ...}, ...}.
|
// map[string]string e.g. {username: password, username: password...}.
|
||||||
// []T which T completes the User interface.
|
// []map[string]interface{} e.g. []{"username": "...", "password": "...", "other_field": ...}, ...}.
|
||||||
// []T which T contains at least Username and Password fields.
|
// []T which T completes the User interface.
|
||||||
|
// []T which T contains at least Username and Password fields.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// New(Options{Allow: AllowUsers(..., [BCRYPT])})
|
// New(Options{Allow: AllowUsers(..., [BCRYPT])})
|
||||||
|
@ -155,15 +157,17 @@ func userMap(usernamePassword map[string]string, opts ...UserAuthOption) AuthFun
|
||||||
// loaded from a file on initialization.
|
// loaded from a file on initialization.
|
||||||
//
|
//
|
||||||
// Example Code:
|
// Example Code:
|
||||||
// New(Options{Allow: AllowUsersFile("users.yml", BCRYPT)})
|
//
|
||||||
|
// New(Options{Allow: AllowUsersFile("users.yml", BCRYPT)})
|
||||||
|
//
|
||||||
// The users.yml file looks like the following:
|
// The users.yml file looks like the following:
|
||||||
// - username: kataras
|
// - username: kataras
|
||||||
// password: kataras_pass
|
// password: kataras_pass
|
||||||
// age: 27
|
// age: 27
|
||||||
// role: admin
|
// role: admin
|
||||||
// - username: makis
|
// - username: makis
|
||||||
// password: makis_password
|
// password: makis_password
|
||||||
// ...
|
// ...
|
||||||
func AllowUsersFile(jsonOrYamlFilename string, opts ...UserAuthOption) AuthFunc {
|
func AllowUsersFile(jsonOrYamlFilename string, opts ...UserAuthOption) AuthFunc {
|
||||||
var (
|
var (
|
||||||
usernamePassword map[string]string
|
usernamePassword map[string]string
|
||||||
|
|
|
@ -2,7 +2,6 @@ package basicauth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -164,7 +163,7 @@ func TestAllowUsers(t *testing.T) {
|
||||||
|
|
||||||
// Test YAML user loading with b-encrypted passwords.
|
// Test YAML user loading with b-encrypted passwords.
|
||||||
func TestAllowUsersFile(t *testing.T) {
|
func TestAllowUsersFile(t *testing.T) {
|
||||||
f, err := ioutil.TempFile("", "*users.yml")
|
f, err := os.CreateTemp("", "*users.yml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,17 +85,18 @@ type (
|
||||||
// please refer to: https://github.com/iris-contrib/middleware repository instead.
|
// please refer to: https://github.com/iris-contrib/middleware repository instead.
|
||||||
//
|
//
|
||||||
// Example Code:
|
// Example Code:
|
||||||
// import "github.com/kataras/iris/v12/middleware/cors"
|
|
||||||
// import "github.com/kataras/iris/v12/x/errors"
|
|
||||||
//
|
//
|
||||||
// app.UseRouter(cors.New().
|
// import "github.com/kataras/iris/v12/middleware/cors"
|
||||||
// HandleErrorFunc(func(ctx iris.Context, err error) {
|
// import "github.com/kataras/iris/v12/x/errors"
|
||||||
// errors.FailedPrecondition.Err(ctx, err)
|
//
|
||||||
// }).
|
// app.UseRouter(cors.New().
|
||||||
// ExtractOriginFunc(cors.StrictOriginExtractor).
|
// HandleErrorFunc(func(ctx iris.Context, err error) {
|
||||||
// ReferrerPolicy(cors.NoReferrerWhenDowngrade).
|
// errors.FailedPrecondition.Err(ctx, err)
|
||||||
// AllowOrigin("domain1.com,domain2.com,domain3.com").
|
// }).
|
||||||
// Handler())
|
// ExtractOriginFunc(cors.StrictOriginExtractor).
|
||||||
|
// ReferrerPolicy(cors.NoReferrerWhenDowngrade).
|
||||||
|
// AllowOrigin("domain1.com,domain2.com,domain3.com").
|
||||||
|
// Handler())
|
||||||
func New() *CORS {
|
func New() *CORS {
|
||||||
return &CORS{
|
return &CORS{
|
||||||
extractOriginFunc: DefaultOriginExtractor,
|
extractOriginFunc: DefaultOriginExtractor,
|
||||||
|
|
|
@ -13,11 +13,12 @@ import (
|
||||||
// The Iris server SHOULD run under HTTP/2 and clients too.
|
// The Iris server SHOULD run under HTTP/2 and clients too.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// import grpcWrapper "github.com/kataras/iris/v12/middleware/grpc"
|
//
|
||||||
// [...]
|
// import grpcWrapper "github.com/kataras/iris/v12/middleware/grpc"
|
||||||
// app := iris.New()
|
// [...]
|
||||||
// grpcServer := grpc.NewServer()
|
// app := iris.New()
|
||||||
// app.WrapRouter(grpcWrapper.New(grpcServer))
|
// grpcServer := grpc.NewServer()
|
||||||
|
// app.WrapRouter(grpcWrapper.New(grpcServer))
|
||||||
func New(grpcServer http.Handler) router.WrapperFunc {
|
func New(grpcServer http.Handler) router.WrapperFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request, mux http.HandlerFunc) {
|
return func(w http.ResponseWriter, r *http.Request, mux http.HandlerFunc) {
|
||||||
if r.ProtoMajor == 2 && strings.HasPrefix(r.Header.Get("Content-Type"), "application/grpc") {
|
if r.ProtoMajor == 2 && strings.HasPrefix(r.Header.Get("Content-Type"), "application/grpc") {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package hcaptcha
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
@ -70,7 +70,9 @@ func New(secret string, options ...Option) context.Handler {
|
||||||
|
|
||||||
// Handler is the HTTP route middleware featured hcaptcha validation.
|
// Handler is the HTTP route middleware featured hcaptcha validation.
|
||||||
// It calls the `SiteVerify` method and fires the "next" when user completed the hcaptcha successfully,
|
// It calls the `SiteVerify` method and fires the "next" when user completed the hcaptcha successfully,
|
||||||
// otherwise it calls the Client's `FailureHandler`.
|
//
|
||||||
|
// otherwise it calls the Client's `FailureHandler`.
|
||||||
|
//
|
||||||
// The hcaptcha's `Response` (which contains any `ErrorCodes`)
|
// The hcaptcha's `Response` (which contains any `ErrorCodes`)
|
||||||
// is saved on the Request's Context (see `GetResponseFromContext`).
|
// is saved on the Request's Context (see `GetResponseFromContext`).
|
||||||
func (c *Client) Handler(ctx *context.Context) {
|
func (c *Client) Handler(ctx *context.Context) {
|
||||||
|
@ -113,7 +115,7 @@ func SiteVerify(ctx *context.Context, secret string) (response Response) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.ErrorCodes = append(response.ErrorCodes, err.Error())
|
response.ErrorCodes = append(response.ErrorCodes, err.Error())
|
||||||
|
|
|
@ -55,14 +55,14 @@ var _ jwt.Blocklist = (*Blocklist)(nil)
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
//
|
//
|
||||||
// blocklist := NewBlocklist()
|
// blocklist := NewBlocklist()
|
||||||
// blocklist.ClientOptions.Addr = ...
|
// blocklist.ClientOptions.Addr = ...
|
||||||
// err := blocklist.Connect()
|
// err := blocklist.Connect()
|
||||||
//
|
//
|
||||||
// And register it:
|
// And register it:
|
||||||
//
|
//
|
||||||
// verifier := jwt.NewVerifier(...)
|
// verifier := jwt.NewVerifier(...)
|
||||||
// verifier.Blocklist = blocklist
|
// verifier.Blocklist = blocklist
|
||||||
func NewBlocklist() *Blocklist {
|
func NewBlocklist() *Blocklist {
|
||||||
return &Blocklist{
|
return &Blocklist{
|
||||||
GetKey: defaultGetKey,
|
GetKey: defaultGetKey,
|
||||||
|
|
|
@ -31,8 +31,8 @@ type Signer struct {
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
//
|
//
|
||||||
// signer := NewSigner(HS256, secret, 15*time.Minute)
|
// signer := NewSigner(HS256, secret, 15*time.Minute)
|
||||||
// token, err := signer.Sign(userClaims{Username: "kataras"})
|
// token, err := signer.Sign(userClaims{Username: "kataras"})
|
||||||
func NewSigner(signatureAlg Alg, signatureKey interface{}, maxAge time.Duration) *Signer {
|
func NewSigner(signatureAlg Alg, signatureKey interface{}, maxAge time.Duration) *Signer {
|
||||||
if signatureAlg == HS256 {
|
if signatureAlg == HS256 {
|
||||||
// A tiny helper if the end-developer uses string instead of []byte for hmac keys.
|
// A tiny helper if the end-developer uses string instead of []byte for hmac keys.
|
||||||
|
|
|
@ -61,24 +61,31 @@ type Verifier struct {
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
//
|
//
|
||||||
// verifier := NewVerifier(HS256, secret)
|
// verifier := NewVerifier(HS256, secret)
|
||||||
// OR
|
|
||||||
// verifier := NewVerifier(HS256, secret, Expected{Issuer: "my-app"})
|
|
||||||
//
|
//
|
||||||
// claimsGetter := func() interface{} { return new(userClaims) }
|
|
||||||
// middleware := verifier.Verify(claimsGetter)
|
|
||||||
// OR
|
// OR
|
||||||
// middleware := verifier.Verify(claimsGetter, Expected{Issuer: "my-app"})
|
//
|
||||||
|
// verifier := NewVerifier(HS256, secret, Expected{Issuer: "my-app"})
|
||||||
|
//
|
||||||
|
// claimsGetter := func() interface{} { return new(userClaims) }
|
||||||
|
// middleware := verifier.Verify(claimsGetter)
|
||||||
|
//
|
||||||
|
// OR
|
||||||
|
//
|
||||||
|
// middleware := verifier.Verify(claimsGetter, Expected{Issuer: "my-app"})
|
||||||
//
|
//
|
||||||
// Register the middleware, e.g.
|
// Register the middleware, e.g.
|
||||||
// app.Use(middleware)
|
//
|
||||||
|
// app.Use(middleware)
|
||||||
//
|
//
|
||||||
// Get the claims:
|
// Get the claims:
|
||||||
// claims := jwt.Get(ctx).(*userClaims)
|
//
|
||||||
// username := claims.Username
|
// claims := jwt.Get(ctx).(*userClaims)
|
||||||
|
// username := claims.Username
|
||||||
//
|
//
|
||||||
// Get the context user:
|
// Get the context user:
|
||||||
// username, err := ctx.User().GetUsername()
|
//
|
||||||
|
// username, err := ctx.User().GetUsername()
|
||||||
func NewVerifier(signatureAlg Alg, signatureKey interface{}, validators ...TokenValidator) *Verifier {
|
func NewVerifier(signatureAlg Alg, signatureKey interface{}, validators ...TokenValidator) *Verifier {
|
||||||
if signatureAlg == HS256 {
|
if signatureAlg == HS256 {
|
||||||
// A tiny helper if the end-developer uses string instead of []byte for hmac keys.
|
// A tiny helper if the end-developer uses string instead of []byte for hmac keys.
|
||||||
|
|
|
@ -166,11 +166,12 @@ func Query(paramName string) Option {
|
||||||
// to determinate the method to override with.
|
// to determinate the method to override with.
|
||||||
//
|
//
|
||||||
// Use cases:
|
// Use cases:
|
||||||
// 1. When need to check only for headers and ignore other fields:
|
|
||||||
// New(Only(Headers("X-Custom-Header")))
|
|
||||||
//
|
//
|
||||||
// 2. When need to check only for (first) form field and (second) custom getter:
|
// 1. When need to check only for headers and ignore other fields:
|
||||||
// New(Only(FormField("fieldName"), Getter(...)))
|
// New(Only(Headers("X-Custom-Header")))
|
||||||
|
//
|
||||||
|
// 2. When need to check only for (first) form field and (second) custom getter:
|
||||||
|
// New(Only(FormField("fieldName"), Getter(...)))
|
||||||
func Only(o ...Option) Option {
|
func Only(o ...Option) Option {
|
||||||
return func(opts *options) {
|
return func(opts *options) {
|
||||||
opts.getters = opts.getters[0:0]
|
opts.getters = opts.getters[0:0]
|
||||||
|
@ -185,7 +186,6 @@ func Only(o ...Option) Option {
|
||||||
// that do not support certain HTTP operations such as DELETE or PUT for security reasons.
|
// that do not support certain HTTP operations such as DELETE or PUT for security reasons.
|
||||||
// This wrapper will accept a method, based on criteria, to override the POST method with.
|
// This wrapper will accept a method, based on criteria, to override the POST method with.
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// Read more at:
|
// Read more at:
|
||||||
// https://github.com/kataras/iris/issues/1325
|
// https://github.com/kataras/iris/issues/1325
|
||||||
func New(opt ...Option) router.WrapperFunc {
|
func New(opt ...Option) router.WrapperFunc {
|
||||||
|
|
|
@ -34,12 +34,13 @@ type Options struct {
|
||||||
// for security reasons.
|
// for security reasons.
|
||||||
//
|
//
|
||||||
// Example Code:
|
// Example Code:
|
||||||
// app.Get("/health", modrevision.New(modrevision.Options{
|
//
|
||||||
// ServerName: "Iris Server",
|
// app.Get("/health", modrevision.New(modrevision.Options{
|
||||||
// Env: "development",
|
// ServerName: "Iris Server",
|
||||||
// Developer: "kataras",
|
// Env: "development",
|
||||||
// TimeLocation: time.FixedZone("Greece/Athens", 10800),
|
// Developer: "kataras",
|
||||||
// }))
|
// TimeLocation: time.FixedZone("Greece/Athens", 7200),
|
||||||
|
// }))
|
||||||
func New(opts Options) context.Handler {
|
func New(opts Options) context.Handler {
|
||||||
buildTime, buildRevision := context.BuildTime, context.BuildRevision
|
buildTime, buildRevision := context.BuildTime, context.BuildRevision
|
||||||
if opts.UnixTime {
|
if opts.UnixTime {
|
||||||
|
|
|
@ -41,7 +41,8 @@ var profileDescriptions = map[string]string{
|
||||||
// New returns a new pprof (profile, cmdline, symbol, goroutine, heap, threadcreate, debug/block) Middleware.
|
// New returns a new pprof (profile, cmdline, symbol, goroutine, heap, threadcreate, debug/block) Middleware.
|
||||||
// Note: Route MUST have the last named parameter wildcard named '{action:path}'.
|
// Note: Route MUST have the last named parameter wildcard named '{action:path}'.
|
||||||
// Example:
|
// Example:
|
||||||
// app.HandleMany("GET", "/debug/pprof /debug/pprof/{action:path}", pprof.New())
|
//
|
||||||
|
// app.HandleMany("GET", "/debug/pprof /debug/pprof/{action:path}", pprof.New())
|
||||||
func New() context.Handler {
|
func New() context.Handler {
|
||||||
return func(ctx *context.Context) {
|
return func(ctx *context.Context) {
|
||||||
if action := ctx.Params().Get("action"); action != "" {
|
if action := ctx.Params().Get("action"); action != "" {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package recaptcha
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -50,7 +50,9 @@ func New(secret string) context.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SiteVerify accepts context and the secret key(https://www.google.com/recaptcha)
|
// SiteVerify accepts context and the secret key(https://www.google.com/recaptcha)
|
||||||
// and returns the google's recaptcha response, if `response.Success` is true
|
//
|
||||||
|
// and returns the google's recaptcha response, if `response.Success` is true
|
||||||
|
//
|
||||||
// then validation passed.
|
// then validation passed.
|
||||||
//
|
//
|
||||||
// Use `New` for middleware use instead.
|
// Use `New` for middleware use instead.
|
||||||
|
@ -74,7 +76,7 @@ func SiteVerify(ctx *context.Context, secret string) (response Response) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
body, err := io.ReadAll(r.Body)
|
||||||
r.Body.Close()
|
r.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.ErrorCodes = append(response.ErrorCodes, err.Error())
|
response.ErrorCodes = append(response.ErrorCodes, err.Error())
|
||||||
|
@ -113,22 +115,24 @@ var recaptchaForm = `<form action="%s" method="POST">
|
||||||
// Example Code:
|
// Example Code:
|
||||||
//
|
//
|
||||||
// Method: "POST" | Path: "/contact"
|
// Method: "POST" | Path: "/contact"
|
||||||
// func postContact(ctx *context.Context) {
|
|
||||||
// // [...]
|
|
||||||
// response := recaptcha.SiteVerify(ctx, recaptchaSecret)
|
|
||||||
//
|
//
|
||||||
// if response.Success {
|
// func postContact(ctx *context.Context) {
|
||||||
// // [your action here, i.e sendEmail(...)]
|
// // [...]
|
||||||
// }
|
// response := recaptcha.SiteVerify(ctx, recaptchaSecret)
|
||||||
//
|
//
|
||||||
// ctx.JSON(response)
|
// if response.Success {
|
||||||
// }
|
// // [your action here, i.e sendEmail(...)]
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ctx.JSON(response)
|
||||||
|
// }
|
||||||
//
|
//
|
||||||
// Method: "GET" | Path: "/contact"
|
// Method: "GET" | Path: "/contact"
|
||||||
// func getContact(ctx *context.Context) {
|
//
|
||||||
// // render the recaptcha form
|
// func getContact(ctx *context.Context) {
|
||||||
// ctx.HTML(recaptcha.GetFormHTML(recaptchaPublic, "/contact"))
|
// // render the recaptcha form
|
||||||
// }
|
// ctx.HTML(recaptcha.GetFormHTML(recaptchaPublic, "/contact"))
|
||||||
|
// }
|
||||||
func GetFormHTML(dataSiteKey string, postActionRelativePath string) string {
|
func GetFormHTML(dataSiteKey string, postActionRelativePath string) string {
|
||||||
return fmt.Sprintf(recaptchaForm, postActionRelativePath, dataSiteKey)
|
return fmt.Sprintf(recaptchaForm, postActionRelativePath, dataSiteKey)
|
||||||
}
|
}
|
||||||
|
|
|
@ -384,9 +384,11 @@ func (c *ControllerActivator) handleHTTPError(funcName string) *router.Route {
|
||||||
//
|
//
|
||||||
// Just like `Party#HandleMany`:, it returns the `[]*router.Routes`.
|
// Just like `Party#HandleMany`:, it returns the `[]*router.Routes`.
|
||||||
// Usage:
|
// Usage:
|
||||||
// func (*Controller) BeforeActivation(b mvc.BeforeActivation) {
|
//
|
||||||
// b.HandleMany("GET", "/path /path1" /path2", "HandlePath")
|
// func (*Controller) BeforeActivation(b mvc.BeforeActivation) {
|
||||||
// }
|
// b.HandleMany("GET", "/path /path1" /path2", "HandlePath")
|
||||||
|
// }
|
||||||
|
//
|
||||||
// HandleMany will override any routes of this "funcName".
|
// HandleMany will override any routes of this "funcName".
|
||||||
func (c *ControllerActivator) HandleMany(method, path, funcName string, middleware ...context.Handler) []*router.Route {
|
func (c *ControllerActivator) HandleMany(method, path, funcName string, middleware ...context.Handler) []*router.Route {
|
||||||
return c.handleMany(method, path, funcName, true, middleware...)
|
return c.handleMany(method, path, funcName, true, middleware...)
|
||||||
|
|
|
@ -86,7 +86,8 @@ func New(party router.Party) *Application {
|
||||||
// this function simply calls the `New(party)` and its `.Configure(configurators...)`.
|
// this function simply calls the `New(party)` and its `.Configure(configurators...)`.
|
||||||
//
|
//
|
||||||
// A call of `mvc.New(app.Party("/path").Configure(buildMyMVC)` is equal to
|
// A call of `mvc.New(app.Party("/path").Configure(buildMyMVC)` is equal to
|
||||||
// `mvc.Configure(app.Party("/path"), buildMyMVC)`.
|
//
|
||||||
|
// `mvc.Configure(app.Party("/path"), buildMyMVC)`.
|
||||||
//
|
//
|
||||||
// Read more at `New() Application` and `Application#Configure` methods.
|
// Read more at `New() Application` and `Application#Configure` methods.
|
||||||
func Configure(party router.Party, configurators ...func(*Application)) *Application {
|
func Configure(party router.Party, configurators ...func(*Application)) *Application {
|
||||||
|
|
|
@ -10,13 +10,13 @@ import (
|
||||||
// It requires a specific "version" constraint for a Controller,
|
// It requires a specific "version" constraint for a Controller,
|
||||||
// e.g. ">1.0.0 <=2.0.0".
|
// e.g. ">1.0.0 <=2.0.0".
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// Usage:
|
// Usage:
|
||||||
// m := mvc.New(dataRouter)
|
//
|
||||||
// m.Handle(new(v1Controller), mvc.Version("1.0.0"), mvc.Deprecated(mvc.DeprecationOptions{}))
|
// m := mvc.New(dataRouter)
|
||||||
// m.Handle(new(v2Controller), mvc.Version("2.3.0"))
|
// m.Handle(new(v1Controller), mvc.Version("1.0.0"), mvc.Deprecated(mvc.DeprecationOptions{}))
|
||||||
// m.Handle(new(v3Controller), mvc.Version(">=3.0.0 <4.0.0"))
|
// m.Handle(new(v2Controller), mvc.Version("2.3.0"))
|
||||||
// m.Handle(new(noVersionController))
|
// m.Handle(new(v3Controller), mvc.Version(">=3.0.0 <4.0.0"))
|
||||||
|
// m.Handle(new(noVersionController))
|
||||||
//
|
//
|
||||||
// See the `versioning` package's documentation for more information on
|
// See the `versioning` package's documentation for more information on
|
||||||
// how the version is extracted from incoming requests.
|
// how the version is extracted from incoming requests.
|
||||||
|
|
|
@ -78,8 +78,13 @@ func (c Config) Validate() Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.SessionIDGenerator == nil {
|
if c.SessionIDGenerator == nil {
|
||||||
c.SessionIDGenerator = func(*context.Context) string {
|
c.SessionIDGenerator = func(ctx *context.Context) string {
|
||||||
id, _ := uuid.NewRandom()
|
id, err := uuid.NewRandom()
|
||||||
|
if err != nil {
|
||||||
|
ctx.StopWithError(400, err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
return id.String()
|
return id.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,24 +94,28 @@ func (s *mem) OnUpdateExpiration(string, time.Duration) error { return nil }
|
||||||
// immutable depends on the store, it may not implement it at all.
|
// immutable depends on the store, it may not implement it at all.
|
||||||
func (s *mem) Set(sid string, key string, value interface{}, _ time.Duration, immutable bool) error {
|
func (s *mem) Set(sid string, key string, value interface{}, _ time.Duration, immutable bool) error {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
s.values[sid].Save(key, value, immutable)
|
store, ok := s.values[sid]
|
||||||
s.mu.RUnlock()
|
s.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
store.Save(key, value, immutable)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mem) Get(sid string, key string) interface{} {
|
func (s *mem) Get(sid string, key string) interface{} {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
v := s.values[sid].Get(key)
|
store, ok := s.values[sid]
|
||||||
s.mu.RUnlock()
|
s.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return store.Get(key)
|
||||||
|
}
|
||||||
|
|
||||||
return v
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mem) Decode(sid string, key string, outPtr interface{}) error {
|
func (s *mem) Decode(sid string, key string, outPtr interface{}) error {
|
||||||
s.mu.RLock()
|
v := s.Get(sid, key)
|
||||||
v := s.values[sid].Get(key)
|
|
||||||
s.mu.RUnlock()
|
|
||||||
if v != nil {
|
if v != nil {
|
||||||
reflect.ValueOf(outPtr).Set(reflect.ValueOf(v))
|
reflect.ValueOf(outPtr).Set(reflect.ValueOf(v))
|
||||||
}
|
}
|
||||||
|
@ -119,29 +123,45 @@ func (s *mem) Decode(sid string, key string, outPtr interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mem) Visit(sid string, cb func(key string, value interface{})) error {
|
func (s *mem) Visit(sid string, cb func(key string, value interface{})) error {
|
||||||
s.values[sid].Visit(cb)
|
s.mu.RLock()
|
||||||
|
store, ok := s.values[sid]
|
||||||
|
s.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
store.Visit(cb)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mem) Len(sid string) int {
|
func (s *mem) Len(sid string) int {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
n := s.values[sid].Len()
|
store, ok := s.values[sid]
|
||||||
s.mu.RUnlock()
|
s.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return store.Len()
|
||||||
|
}
|
||||||
|
|
||||||
return n
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mem) Delete(sid string, key string) (deleted bool) {
|
func (s *mem) Delete(sid string, key string) (deleted bool) {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
deleted = s.values[sid].Remove(key)
|
store, ok := s.values[sid]
|
||||||
s.mu.RUnlock()
|
s.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
deleted = store.Remove(key)
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mem) Clear(sid string) error {
|
func (s *mem) Clear(sid string) error {
|
||||||
s.mu.Lock()
|
s.mu.RLock()
|
||||||
s.values[sid].Reset()
|
store, ok := s.values[sid]
|
||||||
s.mu.Unlock()
|
s.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
store.Reset()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -150,7 +170,6 @@ func (s *mem) Release(sid string) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
delete(s.values, sid)
|
delete(s.values, sid)
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,6 @@ func (p *provider) newSession(man *Sessions, sid string, expires time.Duration)
|
||||||
sid: sid,
|
sid: sid,
|
||||||
Man: man,
|
Man: man,
|
||||||
provider: p,
|
provider: p,
|
||||||
flashes: make(map[string]*flashMessage),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onExpire := func() {
|
onExpire := func() {
|
||||||
|
@ -99,9 +98,10 @@ func (p *provider) EndRequest(ctx *context.Context, session *Session) {
|
||||||
// ErrNotFound may be returned from `UpdateExpiration` of a non-existing or
|
// ErrNotFound may be returned from `UpdateExpiration` of a non-existing or
|
||||||
// invalid session entry from memory storage or databases.
|
// invalid session entry from memory storage or databases.
|
||||||
// Usage:
|
// Usage:
|
||||||
// if err != nil && err.Is(err, sessions.ErrNotFound) {
|
//
|
||||||
// [handle error...]
|
// if err != nil && err.Is(err, sessions.ErrNotFound) {
|
||||||
// }
|
// [handle error...]
|
||||||
|
// }
|
||||||
var ErrNotFound = errors.New("session not found")
|
var ErrNotFound = errors.New("session not found")
|
||||||
|
|
||||||
// UpdateExpiration resets the expiration of a session.
|
// UpdateExpiration resets the expiration of a session.
|
||||||
|
|
|
@ -76,6 +76,7 @@ func (s *Session) runFlashGC() {
|
||||||
delete(s.flashes, key)
|
delete(s.flashes, key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,6 +559,10 @@ func (s *Session) SetImmutable(key string, value interface{}) {
|
||||||
// If you want to define more than one flash messages, you will have to use different keys.
|
// If you want to define more than one flash messages, you will have to use different keys.
|
||||||
func (s *Session) SetFlash(key string, value interface{}) {
|
func (s *Session) SetFlash(key string, value interface{}) {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
|
if s.flashes == nil {
|
||||||
|
s.flashes = make(map[string]*flashMessage)
|
||||||
|
}
|
||||||
|
|
||||||
s.flashes[key] = &flashMessage{value: value}
|
s.flashes[key] = &flashMessage{value: value}
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ func testSessions(t *testing.T, app *iris.Application) {
|
||||||
s := sessions.Get(ctx)
|
s := sessions.Get(ctx)
|
||||||
sessValues := s.GetAll()
|
sessValues := s.GetAll()
|
||||||
|
|
||||||
_, err := ctx.JSON(sessValues)
|
err := ctx.JSON(sessValues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -141,8 +141,7 @@ func TestFlashMessages(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
writeValues := func(ctx *context.Context, values map[string]interface{}) error {
|
writeValues := func(ctx *context.Context, values map[string]interface{}) error {
|
||||||
_, err := ctx.JSON(values)
|
return ctx.JSON(values)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Post("/set", func(ctx *context.Context) {
|
app.Post("/set", func(ctx *context.Context) {
|
||||||
|
|
|
@ -30,25 +30,31 @@ type Group struct {
|
||||||
// any changes to its parent won't affect this one (e.g. register global middlewares afterwards).
|
// any changes to its parent won't affect this one (e.g. register global middlewares afterwards).
|
||||||
//
|
//
|
||||||
// A version is extracted through the versioning.GetVersion function:
|
// A version is extracted through the versioning.GetVersion function:
|
||||||
// Accept-Version: 1.0.0
|
|
||||||
// Accept: application/json; version=1.0.0
|
|
||||||
// You can customize it by setting a version based on the request context:
|
|
||||||
// api.Use(func(ctx *context.Context) {
|
|
||||||
// if version := ctx.URLParam("version"); version != "" {
|
|
||||||
// SetVersion(ctx, version)
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// ctx.Next()
|
// Accept-Version: 1.0.0
|
||||||
// })
|
// Accept: application/json; version=1.0.0
|
||||||
|
//
|
||||||
|
// You can customize it by setting a version based on the request context:
|
||||||
|
//
|
||||||
|
// api.Use(func(ctx *context.Context) {
|
||||||
|
// if version := ctx.URLParam("version"); version != "" {
|
||||||
|
// SetVersion(ctx, version)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ctx.Next()
|
||||||
|
// })
|
||||||
|
//
|
||||||
// OR:
|
// OR:
|
||||||
// api.Use(versioning.FromQuery("version", ""))
|
//
|
||||||
|
// api.Use(versioning.FromQuery("version", ""))
|
||||||
//
|
//
|
||||||
// Examples at: _examples/routing/versioning
|
// Examples at: _examples/routing/versioning
|
||||||
// Usage:
|
// Usage:
|
||||||
// app := iris.New()
|
//
|
||||||
// api := app.Party("/api")
|
// app := iris.New()
|
||||||
// v1 := versioning.NewGroup(api, ">=1.0.0 <2.0.0")
|
// api := app.Party("/api")
|
||||||
// v1.Get/Post/Put/Delete...
|
// v1 := versioning.NewGroup(api, ">=1.0.0 <2.0.0")
|
||||||
|
// v1.Get/Post/Put/Delete...
|
||||||
//
|
//
|
||||||
// Valid ranges are:
|
// Valid ranges are:
|
||||||
// - "<1.0.0"
|
// - "<1.0.0"
|
||||||
|
@ -61,8 +67,10 @@ type Group struct {
|
||||||
// A Range can consist of multiple ranges separated by space:
|
// A Range can consist of multiple ranges separated by space:
|
||||||
// Ranges can be linked by logical AND:
|
// Ranges can be linked by logical AND:
|
||||||
// - ">1.0.0 <2.0.0" would match between both ranges, so "1.1.1" and "1.8.7"
|
// - ">1.0.0 <2.0.0" would match between both ranges, so "1.1.1" and "1.8.7"
|
||||||
|
//
|
||||||
// but not "1.0.0" or "2.0.0"
|
// but not "1.0.0" or "2.0.0"
|
||||||
// - ">1.0.0 <3.0.0 !2.0.3-beta.2" would match every version between 1.0.0 and 3.0.0
|
// - ">1.0.0 <3.0.0 !2.0.3-beta.2" would match every version between 1.0.0 and 3.0.0
|
||||||
|
//
|
||||||
// except 2.0.3-beta.2
|
// except 2.0.3-beta.2
|
||||||
//
|
//
|
||||||
// Ranges can also be linked by logical OR:
|
// Ranges can also be linked by logical OR:
|
||||||
|
@ -72,7 +80,8 @@ type Group struct {
|
||||||
//
|
//
|
||||||
// Ranges can be combined by both AND and OR
|
// Ranges can be combined by both AND and OR
|
||||||
//
|
//
|
||||||
// - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`,
|
// - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`,
|
||||||
|
//
|
||||||
// but not `4.2.1`, `2.1.1`
|
// but not `4.2.1`, `2.1.1`
|
||||||
func NewGroup(r API, version string) *Group {
|
func NewGroup(r API, version string) *Group {
|
||||||
version = strings.ReplaceAll(version, ",", " ")
|
version = strings.ReplaceAll(version, ",", " ")
|
||||||
|
|
|
@ -187,11 +187,13 @@ func GetVersion(ctx *context.Context) string {
|
||||||
// It can be used inside a middleware.
|
// It can be used inside a middleware.
|
||||||
// Example of how you can change the default behavior to extract a requested version (which is by headers)
|
// Example of how you can change the default behavior to extract a requested version (which is by headers)
|
||||||
// from a "version" url parameter instead:
|
// from a "version" url parameter instead:
|
||||||
// func(ctx iris.Context) { // &version=1
|
//
|
||||||
// version := ctx.URLParamDefault("version", "1.0.0")
|
// func(ctx iris.Context) { // &version=1
|
||||||
// versioning.SetVersion(ctx, version)
|
// version := ctx.URLParamDefault("version", "1.0.0")
|
||||||
// ctx.Next()
|
// versioning.SetVersion(ctx, version)
|
||||||
// }
|
// ctx.Next()
|
||||||
|
// }
|
||||||
|
//
|
||||||
// See `GetVersion` too.
|
// See `GetVersion` too.
|
||||||
func SetVersion(ctx *context.Context, constraint string) {
|
func SetVersion(ctx *context.Context, constraint string) {
|
||||||
ctx.Values().Set(ctx.Application().ConfigurationReadOnly().GetVersionContextKey(), constraint)
|
ctx.Values().Set(ctx.Application().ConfigurationReadOnly().GetVersionContextKey(), constraint)
|
||||||
|
@ -205,23 +207,24 @@ type AliasMap = map[string]string
|
||||||
// for the children Parties(routers). It's respected by versioning Groups.
|
// for the children Parties(routers). It's respected by versioning Groups.
|
||||||
//
|
//
|
||||||
// Example Code:
|
// Example Code:
|
||||||
// app := iris.New()
|
|
||||||
//
|
//
|
||||||
// api := app.Party("/api")
|
// app := iris.New()
|
||||||
// api.Use(Aliases(map[string]string{
|
|
||||||
// versioning.Empty: "1.0.0", // when no version was provided by the client.
|
|
||||||
// "beta": "4.0.0",
|
|
||||||
// "stage": "5.0.0-alpha"
|
|
||||||
// }))
|
|
||||||
//
|
//
|
||||||
// v1 := NewGroup(api, ">=1.0.0 < 2.0.0")
|
// api := app.Party("/api")
|
||||||
// v1.Get/Post...
|
// api.Use(Aliases(map[string]string{
|
||||||
|
// versioning.Empty: "1.0.0", // when no version was provided by the client.
|
||||||
|
// "beta": "4.0.0",
|
||||||
|
// "stage": "5.0.0-alpha"
|
||||||
|
// }))
|
||||||
//
|
//
|
||||||
// v4 := NewGroup(api, ">=4.0.0 < 5.0.0")
|
// v1 := NewGroup(api, ">=1.0.0 < 2.0.0")
|
||||||
// v4.Get/Post...
|
// v1.Get/Post...
|
||||||
//
|
//
|
||||||
// stage := NewGroup(api, "5.0.0-alpha")
|
// v4 := NewGroup(api, ">=4.0.0 < 5.0.0")
|
||||||
// stage.Get/Post...
|
// v4.Get/Post...
|
||||||
|
//
|
||||||
|
// stage := NewGroup(api, "5.0.0-alpha")
|
||||||
|
// stage.Get/Post...
|
||||||
func Aliases(aliases AliasMap) context.Handler {
|
func Aliases(aliases AliasMap) context.Handler {
|
||||||
cp := make(AliasMap, len(aliases)) // copy the map here so we are safe of later modifications by end-dev.
|
cp := make(AliasMap, len(aliases)) // copy the map here so we are safe of later modifications by end-dev.
|
||||||
for k, v := range aliases {
|
for k, v := range aliases {
|
||||||
|
|
|
@ -50,7 +50,8 @@ type (
|
||||||
// through a Context or within filter functions.
|
// through a Context or within filter functions.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// AsValue("my string")
|
//
|
||||||
|
// AsValue("my string")
|
||||||
//
|
//
|
||||||
// Shortcut for `pongo2.AsValue`.
|
// Shortcut for `pongo2.AsValue`.
|
||||||
var AsValue = pongo2.AsValue
|
var AsValue = pongo2.AsValue
|
||||||
|
|
|
@ -2,7 +2,7 @@ package view
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -80,7 +80,7 @@ func asset(fs http.FileSystem, name string) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
contents, err := ioutil.ReadAll(f)
|
contents, err := io.ReadAll(f)
|
||||||
f.Close()
|
f.Close()
|
||||||
return contents, err
|
return contents, err
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user